Эх сурвалжийг харах

Merge branch 'dev' of http://219.151.181.73:3000/zhuwei/bladex into dev

laibulaizheli 1 долоо хоног өмнө
parent
commit
3cfb2a4f59
15 өөрчлөгдсөн 570 нэмэгдсэн , 124 устгасан
  1. 1 1
      blade-common/src/main/java/org/springblade/common/utils/AsyncConfig.java
  2. 6 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/InformationQuery.java
  3. 3 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ImageClassificationFileClient.java
  4. 1 1
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/AlbumDTO.java
  5. 9 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/AlbumDTO1.java
  6. 2 1
      blade-service-api/blade-user-api/src/main/java/org/springblade/system/user/feign/IUserClient.java
  7. 21 3
      blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java
  8. 43 40
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  9. 8 0
      blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ImageClassificationFileClientImpl.java
  10. 5 35
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  11. 125 32
      blade-service/blade-business/src/main/java/org/springblade/business/sync/TaskSync.java
  12. 180 11
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/AlbumController.java
  13. 88 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/FileUtils.java
  14. 64 0
      blade-service/blade-user/src/main/java/org/springblade/system/user/controller/UserController.java
  15. 14 0
      blade-service/blade-user/src/main/java/org/springblade/system/user/feign/UserClient.java

+ 1 - 1
blade-common/src/main/java/org/springblade/common/utils/AsyncConfig.java

@@ -20,7 +20,7 @@ public class AsyncConfig {
     public ThreadPoolExecutor getAsyncExecutor() {
         return new ThreadPoolMonitor(cpuNum
                 , 15
-                , 180
+                , 600
                 , TimeUnit.SECONDS
                 , new LinkedBlockingQueue<>(2000)
                 , new ThreadPoolExecutor.DiscardOldestPolicy(), "manager-thread-pool");

+ 6 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/InformationQuery.java

@@ -137,4 +137,10 @@ public class InformationQuery extends BaseEntity {
 
     @ApiModelProperty("节点pdf")
     private String nodePdfUrl;
+
+    @ApiModelProperty("重刷状态 0-待重刷,1-正在重刷,2-重刷成功,3-重刷失败")
+    private Integer saveAgain;
+
+    @ApiModelProperty("重刷次数:如果次数大于5次 每次都是3,就停止重刷")
+    private Integer saveAgainCount;
 }

+ 3 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/feign/ImageClassificationFileClient.java

@@ -1,6 +1,7 @@
 package org.springblade.business.feign;
 
 import org.springblade.business.dto.ImageClassificationFileDTO;
+import org.springblade.business.entity.ImageClassificationFile;
 import org.springblade.common.constant.BusinessConstant;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -25,4 +26,6 @@ public interface ImageClassificationFileClient {
     @PostMapping(API_PREFIX + "/getImageClassificationFileListByContractId")
     List<ImageClassificationFileDTO> getImageClassificationFileListByContractId(@RequestBody Long contractId);
 
+    @PostMapping(API_PREFIX + "/getImageClassificationFileById")
+    ImageClassificationFile getImageClassificationFileById(@RequestBody Long id);
 }

+ 1 - 1
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/AlbumDTO.java

@@ -33,7 +33,7 @@ import java.util.List;
 public class AlbumDTO extends Album {
 	private static final long serialVersionUID = 1L;
 
-	private List<String> margePdfUrls;
+	private List<AlbumDTO1> margePdfUrls;
 
 	private String dateValue;
 

+ 9 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/AlbumDTO1.java

@@ -0,0 +1,9 @@
+package org.springblade.manager.dto;
+
+import lombok.Data;
+
+@Data
+public class AlbumDTO1 {
+    private Long id;
+    private String imageUrl;
+}

+ 2 - 1
blade-service-api/blade-user-api/src/main/java/org/springblade/system/user/feign/IUserClient.java

@@ -185,5 +185,6 @@ public interface IUserClient {
     @GetMapping(API_PREFIX + "/clearContractLocalCacheAndRedisCache")
     void clearContractLocalCacheAndRedisCache();
 
-
+    @GetMapping(API_PREFIX + "/getTokenByUser")
+    String getTokenByUser(@RequestParam String account);
 }

+ 21 - 3
blade-service/blade-archive/src/main/java/org/springblade/archive/controller/ArchivesAutoController.java

@@ -210,7 +210,7 @@ public class ArchivesAutoController extends BladeController {
 		String templatePath = "/mnt/sdc/Users/hongchuangyanfa/Desktop/excel/archiveTemplate.xlsx";
 		//String templatePath="C:\\Users\\hc01\\Desktop\\archiveTemplate.xlsx";
 		InputStream templateStream = new FileInputStream(new File(templatePath));
-		org.apache.poi.ss.usermodel.Workbook workbook = WorkbookFactory.create(templateStream);
+		Workbook workbook = WorkbookFactory.create(templateStream);
 		Sheet sheet = workbook.getSheetAt(0);
 
 		// 创建带边框的单元格样式
@@ -632,8 +632,26 @@ public class ArchivesAutoController extends BladeController {
 			return R.fail("请选择多个案卷进行合并");
 		}
 		archivesAutoList.sort(Comparator.comparingInt(a -> {
-			String[] parts = a.getFileNumber().split("_");
-			return Integer.parseInt(parts[parts.length - 1]); // 取最后一个部分作为数字
+			String fileNumber = a.getFileNumber();
+			if (fileNumber == null || fileNumber.isEmpty()) {
+				return Integer.MAX_VALUE;
+			}
+			String[] parts;
+			if (fileNumber.indexOf("_") > 0) {
+				parts = fileNumber.split("_");
+			} else if (fileNumber.indexOf("-") > 0) {
+				parts = fileNumber.split("-");
+			} else {
+				return Integer.MAX_VALUE;
+			}
+			if (parts.length > 0) {
+				try {
+					return Integer.parseInt(parts[parts.length - 1]);
+				} catch (NumberFormatException e) {
+					return Integer.MAX_VALUE;
+				}
+			}
+			return Integer.MAX_VALUE;
 		}));
 		//根据档号后缀排序 拿到第一个
 		ArchivesAuto auto = archivesAutoList.get(0);

+ 43 - 40
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -1527,48 +1527,51 @@ public class TaskController extends BladeController {
                             Task::getId,
                             task -> task));
         }
-        //所有满足条件的日志 转map
-        String logQuery = "select business_id,create_user_name ,create_time, operation_type, save_data from u_operation_log where operation_type in (6,9,12,15,18,21,24,26,61,62)";
-        List<OperationLog> operationLogs = jdbcTemplate.query(logQuery, new BeanPropertyRowMapper<>(OperationLog.class));
-        if(ObjectUtil.isNotEmpty(operationLogs)){
-             operationLogMap = operationLogs.stream().collect(Collectors.groupingBy(OperationLog::getBusinessId));
-        }
-        for (BusinessTaskPageVO businessTaskPageVO : pageList) {
-            if("已废除".equals(businessTaskPageVO.getTaskStatusName())){
-                Long taskId = businessTaskPageVO.getTaskId();
-                Task task = taskMap.get(taskId);
-                if (ObjectUtil.isEmpty(task)){
-                    continue;
-                }
-                //任务创建时间
-                Date createTime = task.getCreateTime();
-                //废除时间肯定在任务创建时间之后  选择距离当前任务创建时间最近的一条数据
-                List<OperationLog> operationLogsF = operationLogMap.get(task.getFormDataId());
-
-                if(ObjectUtil.isNotEmpty(operationLogsF)){
-                    Optional<OperationLog> min = operationLogsF.stream().filter(o -> o.getCreateTime().compareTo(createTime) >= 0)
-                            .min(Comparator.comparing(t -> t.getCreateTime().getTime() - createTime.getTime()));
-                    if (min.isPresent()){
-                        OperationLog operationLog = min.get();
-                        String createUserName = operationLog.getCreateUserName();
-                        String date = DateUtil.formatDateTime(operationLog.getCreateTime());
-                        if (operationLog.getOperationType() != null && operationLog.getOperationType() == 61) {
-                            businessTaskPageVO.setEVisaStatus("驳回成功:"+ createUserName +"-"+ date);
-                            String saveData = operationLog.getSaveData();
-                            if (saveData != null && !saveData.isEmpty()) {
-                                try  {
-                                    JSONObject data = JSONObject.parseObject(saveData);
-                                    if (data != null && data.containsKey("comment")) {
-                                        businessTaskPageVO.setEVisaStatus("驳回成功:"+ createUserName +"-"+ date + ";驳回原因:"+data.getString("comment"));
+        if(CollectionUtil.isNotEmpty(pageList)){
+            //所有满足条件的日志 转map
+            Set<String> collect = pageList.stream().map(BusinessTaskPageVO::getFormDataId).collect(Collectors.toSet());
+            String logQuery = "select business_id,create_user_name ,create_time, operation_type, save_data from u_operation_log where business_id in (" + StringUtil.join(collect) + ") and operation_type in (6,9,12,15,18,21,24,26,61,62)";
+            List<OperationLog> operationLogs = jdbcTemplate.query(logQuery, new BeanPropertyRowMapper<>(OperationLog.class));
+            if(ObjectUtil.isNotEmpty(operationLogs)){
+                operationLogMap = operationLogs.stream().collect(Collectors.groupingBy(OperationLog::getBusinessId));
+            }
+            for (BusinessTaskPageVO businessTaskPageVO : pageList) {
+                if("已废除".equals(businessTaskPageVO.getTaskStatusName())){
+                    Long taskId = businessTaskPageVO.getTaskId();
+                    Task task = taskMap.get(taskId);
+                    if (ObjectUtil.isEmpty(task)){
+                        continue;
+                    }
+                    //任务创建时间
+                    Date createTime = task.getCreateTime();
+                    //废除时间肯定在任务创建时间之后  选择距离当前任务创建时间最近的一条数据
+                    List<OperationLog> operationLogsF = operationLogMap.get(task.getFormDataId());
+
+                    if(ObjectUtil.isNotEmpty(operationLogsF)){
+                        Optional<OperationLog> min = operationLogsF.stream().filter(o -> o.getCreateTime().compareTo(createTime) >= 0)
+                                .min(Comparator.comparing(t -> t.getCreateTime().getTime() - createTime.getTime()));
+                        if (min.isPresent()){
+                            OperationLog operationLog = min.get();
+                            String createUserName = operationLog.getCreateUserName();
+                            String date = DateUtil.formatDateTime(operationLog.getCreateTime());
+                            if (operationLog.getOperationType() != null && operationLog.getOperationType() == 61) {
+                                businessTaskPageVO.setEVisaStatus("驳回成功:"+ createUserName +"-"+ date);
+                                String saveData = operationLog.getSaveData();
+                                if (saveData != null && !saveData.isEmpty()) {
+                                    try  {
+                                        JSONObject data = JSONObject.parseObject(saveData);
+                                        if (data != null && data.containsKey("comment")) {
+                                            businessTaskPageVO.setEVisaStatus("驳回成功:"+ createUserName +"-"+ date + ";驳回原因:"+data.getString("comment"));
+                                        }
+                                    } catch (Exception e) {
+                                        e.printStackTrace();
                                     }
-                                } catch (Exception e) {
-                                    e.printStackTrace();
                                 }
+                            } else if (operationLog.getOperationType() != null && operationLog.getOperationType() == 62) {
+                                businessTaskPageVO.setEVisaStatus("撤回成功:"+ createUserName +"-"+ date);
+                            } else {
+                                businessTaskPageVO.setEVisaStatus(businessTaskPageVO.getEVisaStatus()+":"+ createUserName +"-"+ date);
                             }
-                        } else if (operationLog.getOperationType() != null && operationLog.getOperationType() == 62) {
-                            businessTaskPageVO.setEVisaStatus("撤回成功:"+ createUserName +"-"+ date);
-                        } else {
-                            businessTaskPageVO.setEVisaStatus(businessTaskPageVO.getEVisaStatus()+":"+ createUserName +"-"+ date);
                         }
                     }
                 }
@@ -2126,7 +2129,7 @@ public class TaskController extends BladeController {
     /**
      * 任务超时提示信息
      */
-    @Scheduled(cron = "0 0 3 * * ?")
+//    @Scheduled(cron = "0 0 3 * * ?")
     public void TaskTimeoutTips() {
         String key = "task.time.out";
         String value = ParamCache.getValue(key);

+ 8 - 0
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ImageClassificationFileClientImpl.java

@@ -2,8 +2,10 @@ package org.springblade.business.feignClient;
 
 import lombok.AllArgsConstructor;
 import org.springblade.business.dto.ImageClassificationFileDTO;
+import org.springblade.business.entity.ImageClassificationFile;
 import org.springblade.business.feign.ImageClassificationFileClient;
 import org.springblade.business.mapper.ImageClassificationFileMapper;
+import org.springblade.business.service.IImageClassificationFileService;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
@@ -13,10 +15,16 @@ import java.util.List;
 public class ImageClassificationFileClientImpl implements ImageClassificationFileClient {
 
     private final ImageClassificationFileMapper imageClassificationFileMapper;
+    private final IImageClassificationFileService imageClassificationFileService;
 
     @Override
     public List<ImageClassificationFileDTO> getImageClassificationFileListByContractId(Long contractId) {
         return imageClassificationFileMapper.getImageClassificationFileListByContractId(contractId);
     }
 
+    @Override
+    public ImageClassificationFile getImageClassificationFileById(Long id) {
+        return imageClassificationFileService.getById(id);
+    }
+
 }

+ 5 - 35
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java

@@ -138,12 +138,6 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
 
     @Autowired
     StringRedisTemplate RedisTemplate;
-    @Autowired
-    private BladeRedis bladeRedis;
-    //异步类
-    @Autowired
-    private TaskSync taskSync;
-
 
 
     private final ITrialSelfInspectionRecordService iTrialSelfInspectionRecordService;
@@ -1978,37 +1972,13 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
     }*/
         @Override
         public R reSigningEVisaStatus0(List<reSigningEVisaStatus> dtos, String header) throws Exception {
-         R result= new R();
          if(dtos.size()>0){
-
-             //添加缓存
              Set<Long> newIds = dtos.stream().map(reSigningEVisaStatus::getId).collect(Collectors.toSet());
-
-             //随机id
-             String s = "sign-reSigningEVisaStatus0:" + SnowFlakeUtil.getId();
-
-             //数据效验
-             Set<Long> oldIds = new HashSet<>();
-             Set<String> keys = bladeRedis.keys("sign-reSigningEVisaStatus0*");
-             for (String key : keys) {
-                 Set<Long> ids = bladeRedis.get(key);
-                 if(ids !=null ){
-                     oldIds.addAll(ids);
-                 }
-             }
-
-             if(CollectionUtils.isNotEmpty(oldIds)){
-                 //如果旧的id中存在新的id,则不允许添加
-                 long count = oldIds.stream().filter(f -> newIds.contains(f)).count();
-                 if(count > 0){
-                     return R.fail("当前提交数据中存在正在保存的数据,请勿重复提交");
-                 }
-             }
-             //10分钟过期
-             bladeRedis.setEx(s,newIds, 600L);
-
-             //执行异步
-             taskSync.reSigningEVisaStatusSync(dtos,header,s);
+             //正在重刷的不允许再次重刷
+             informationQueryService.update(Wrappers.<InformationQuery>update().lambda()
+                     .set(InformationQuery::getSaveAgain, 0)
+                     .ne(InformationQuery::getSaveAgain, 1)
+                     .in(InformationQuery::getId, newIds));
         }
          return R.success("操作成功");
     }

+ 125 - 32
blade-service/blade-business/src/main/java/org/springblade/business/sync/TaskSync.java

@@ -1,7 +1,13 @@
 package org.springblade.business.sync;
 
+import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.collect.Lists;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springblade.business.dto.reSigningEVisaStatus;
 import org.springblade.business.entity.InformationQuery;
 import org.springblade.business.service.IInformationQueryFileService;
@@ -9,60 +15,147 @@ import org.springblade.business.service.IInformationQueryService;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.api.R;
+import org.springblade.manager.entity.WbsTreeSynchronousRecord;
 import org.springblade.manager.feign.ExcelTabClient;
+import org.springblade.system.user.feign.IUserClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
 
 /**
  * @author LHB
  */
 @Component
 @AllArgsConstructor
+@Slf4j
 public class TaskSync {
 
     private final IInformationQueryService informationQueryService;
-
     private final ExcelTabClient excelTabClient;
-    @Autowired
-    private BladeRedis bladeRedis;
-    @Async("taskExecutor1")
-    public void reSigningEVisaStatusSync(List<reSigningEVisaStatus> dtos, String header,String s) {
-        R result= null;
-        try {
-            for (reSigningEVisaStatus dto : dtos) {
-                InformationQuery iq = informationQueryService.getById(dto.getId());
-                if(iq!=null){
-                    informationQueryService.update(new LambdaUpdateWrapper<InformationQuery>()
-                            .eq(InformationQuery::getId, dto.getId())
-                            .set(InformationQuery::getEVisaPdfUrl, null)
-                            .set(InformationQuery::getPdfUrl, null));
+    // 线程池
+    @Resource(name = "taskExecutor1")
+    private ThreadPoolExecutor executor;
+
+    //用户
+    @Resource
+    private IUserClient userClient;
+
+
+    public void reSigningEVisaStatusSync(InformationQuery dto, String header) {
+        log.info("数据正在重刷,线程名称:{}", Thread.currentThread().getName());
+
+        informationQueryService.update(new LambdaUpdateWrapper<InformationQuery>()
+                .eq(InformationQuery::getId, dto.getId())
+                .set(InformationQuery::getEVisaPdfUrl, null)
+                .set(InformationQuery::getUpdateTime, DateTime.now())
+
+                .set(InformationQuery::getPdfUrl, null));
+        R result = this.saveNodePdf(dto.getClassify() + "", dto.getWbsId() + "", dto.getContractId() + "", dto.getProjectId() + "", header);
+
+        LambdaUpdateWrapper<InformationQuery> lambda = Wrappers.<InformationQuery>update().lambda();
+        if (result == null || result.getCode() != 200) {
+            //重签失败
+            lambda.set(InformationQuery::getSaveAgain, 3)
+                    .set(InformationQuery::getEVisaPdfUrl, dto.getEVisaPdfUrl())
+                    .setSql("save_again_count = save_again_count + 1")
+                    .set(InformationQuery::getPdfUrl, dto.getPdfUrl());
+        } else {
+            //成功重签
+            lambda.set(InformationQuery::getSaveAgain, 2);
+        }
+        lambda.set(InformationQuery::getUpdateTime, DateTime.now());
+        lambda.eq(InformationQuery::getId, dto.getId());
+
+        informationQueryService.update(lambda);
+        log.info("数据重刷完毕,线程名称:{}", Thread.currentThread().getName());
+    }
+
+
+    /**
+     * 定时检查save-again = 1 的数据 查看更新时间与当前时间是否超过30分钟,如果超过 30分钟,则修改状态为0
+     * 一个小时检查一次
+     */
+    @Scheduled(cron = "0 0 * * * ?")
+    public void updateStuckTask() {
+        List<InformationQuery> list = informationQueryService.list(Wrappers.<InformationQuery>lambdaQuery()
+                .eq(InformationQuery::getSaveAgain, 1)
+                .eq(InformationQuery::getIsDeleted, 0));
+
+        List<Long> ids = new ArrayList<>();
+        for (InformationQuery informationQuery : list) {
+            //更新时间 + 半个小时 < 当前时间
+            if (informationQuery.getUpdateTime().getTime() + 1800000 < System.currentTimeMillis()) {
+                ids.add(informationQuery.getId());
+            }
+        }
+        if (CollectionUtils.isNotEmpty(ids)) {
+            informationQueryService.update(null, Wrappers.<InformationQuery>lambdaUpdate()
+                    .set(InformationQuery::getSaveAgain, 0)
+                    .in(InformationQuery::getId, ids));
+        }
+    }
+
+
+    /**
+     * 重刷定时任务 使用多线程的方式去跑
+     */
+    @Scheduled(fixedDelay = 60000)
+    public void saveAgainTask() {
+        //获取token
+        String header = userClient.getTokenByUser("admin");
+
+        List<InformationQuery> list = informationQueryService.list(Wrappers.<InformationQuery>lambdaQuery()
+                .in(InformationQuery::getSaveAgain, 0, 3)
+                .eq(InformationQuery::getIsDeleted, 0)
+                //失败重刷次数小于2次
+                .lt(InformationQuery::getSaveAgainCount, 2)
+                .last("limit 50"));
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+
+        for (InformationQuery informationQueries : list) {
+            //修改状态之后开始重刷
+            boolean update = informationQueryService.update(Wrappers.<InformationQuery>update().lambda()
+                    .set(InformationQuery::getSaveAgain, 1)
+                    .set(InformationQuery::getUpdateTime, DateTime.now())
+                    .eq(InformationQuery::getId, informationQueries.getId()));
+            if (update) {
+                CompletableFuture.runAsync(() -> {
                     try {
-                        result = this.saveNodePdf(iq.getClassify() + "", iq.getWbsId() + "", dto.getContractId() + "", dto.getProjectId() + "", header);
-                        if (result == null || (result != null && result.getCode() != 200)) {
-                           throw new ServiceException(iq.getName() + "重新保存PDF信息失败");
-                        }
+                        /*===============执行批量任务===============*/
+                        this.reSigningEVisaStatusSync(informationQueries, header);
                     } catch (Exception e) {
-                        e.printStackTrace();
-                        //如果失败 修改pdf和e_visa_pdf_url 路径
-                        informationQueryService.update(new LambdaUpdateWrapper<InformationQuery>()
-                                .eq(InformationQuery::getId, dto.getId())
-                                .set(InformationQuery::getEVisaPdfUrl, iq.getEVisaPdfUrl())
-                                .set(InformationQuery::getPdfUrl, iq.getPdfUrl()));
+                        log.error("执行重刷任务失败,任务ID列表:{}", informationQueries.getId(), e);
+                        // 可选:回滚状态或标记为失败
                     }
-                }
+                }, executor).exceptionally(throwable -> {
+                    log.error("异步任务执行异常,任务ID列表:{}", informationQueries.getId(), throwable);
+                    return null;
+                });
             }
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }finally {
-            //删除缓f存
-            bladeRedis.del(s);
         }
+        log.info("队列数量{}", executor.getQueue().size());
+        log.info("活跃数量{}", executor.getActiveCount());
+        log.info("总共数量{}", executor.getTaskCount());
+        log.info("完成数量{}", executor.getCompletedTaskCount());
     }
 
-    R saveNodePdf(String classify, String nodePKeyIds, String contractId, String projectId, String header) throws Exception {
-        return excelTabClient.synPDFInfo(contractId, nodePKeyIds, classify, projectId, header);
+
+    R saveNodePdf(String classify, String nodePKeyIds, String contractId, String projectId, String header) {
+        try {
+            return excelTabClient.synPDFInfo(contractId, nodePKeyIds, classify, projectId, header);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
     }
 }

+ 180 - 11
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/AlbumController.java

@@ -16,7 +16,11 @@
  */
 package org.springblade.manager.controller;
 
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.nacos.common.utils.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -24,8 +28,15 @@ import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 import javax.validation.Valid;
 
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.util.IOUtils;
+import org.springblade.business.entity.ImageClassificationFile;
+import org.springblade.business.feign.ImageClassificationFileClient;
 import org.springblade.common.constant.CommonConstant;
+import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.common.utils.SystemUtils;
+import org.springblade.common.vo.DataVO;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
@@ -33,10 +44,19 @@ import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.BeanUtil;
 import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.IoUtil;
+import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.manager.dto.AlbumDTO;
+import org.springblade.manager.dto.AlbumDTO1;
+import org.springblade.manager.entity.ExcelTab;
+import org.springblade.manager.feign.ExcelTabClient;
+import org.springblade.manager.feign.ImageClassificationConfigClient;
 import org.springblade.manager.utils.FileUtils;
+import org.springblade.resource.feign.CommonFileClient;
 import org.springblade.resource.feign.NewIOSSClient;
+import org.springblade.resource.vo.NewBladeFile;
 import org.springblade.system.cache.ParamCache;
+import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -45,6 +65,16 @@ import org.springblade.manager.vo.AlbumVO;
 import org.springblade.manager.wrapper.AlbumWrapper;
 import org.springblade.manager.service.IAlbumService;
 import org.springblade.core.boot.ctrl.BladeController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
 
 /**
  *  控制器
@@ -62,6 +92,12 @@ public class AlbumController extends BladeController {
 
 	private final NewIOSSClient newIOSSClient;
 
+	private final ExcelTabClient excelTabClient;
+
+	private final ImageClassificationFileClient imageClassificationFileClient;
+
+	private final CommonFileClient commonFileClient;
+
 	/**
 	 * 详情
 	 */
@@ -106,26 +142,159 @@ public class AlbumController extends BladeController {
 		if(albumDTO.getMargePdfUrls().isEmpty()){
 			throw new ServiceException("相册不能为空");
 		}
+		List<String>uris=new ArrayList<>();
+		HashMap<String, Long> map = new HashMap<>();
+		for (AlbumDTO1 margePdfUrl : albumDTO.getMargePdfUrls()) {
+			String imageUrl = margePdfUrl.getImageUrl();
+			String[] urlss = imageUrl.split(",");
+			for (String string : urlss) {
+				map.put(string,margePdfUrl.getId());
+				uris.add(string);
+			}
+		}
+		if(uris.isEmpty()){
+			throw new ServiceException("相册不能为空");
+		}
 		Album album=new Album();
 		BeanUtil.copy(albumDTO,album);
 		String dateValue = albumDTO.getDateValue();
 		String[] strings = dateValue.split("~");
 		album.setStartDate(strings[0]);
 		album.setEndDate(strings[1]);
-		if(albumDTO.getMargePdfUrls().size()>1){
-			String file_path = FileUtils.getSysLocalFileUrl();
-			Long id = SnowFlakeUtil.getId();
-			String mergeName=id+".pdf";
-			String mergeUrl = file_path + "/nodePDF/"+id+".pdf";;
-			FileUtils.mergePdfPublicMethods(albumDTO.getMargePdfUrls(), mergeUrl);
-			BladeFile bladeFile = this.newIOSSClient.uploadFile(mergeName, mergeUrl);
-			if (bladeFile != null && ObjectUtils.isNotEmpty(bladeFile.getLink())) {
-				album.setImagesPdf(bladeFile.getLink());
+		//获取固定表格
+		ExcelTab excelTab = this.excelTabClient.getById("1550363881879781377"); //影像资料模板
+		String file_path = null;
+		if (SystemUtils.isWindows()) {
+			file_path = "C:\\pdfFiles\\";
+			File file = new File(file_path);
+			if (!file.exists()) {
+				file.mkdirs();
+			}
+		}
+		if (SystemUtils.isLinux()) {
+			file_path = "/home/pdfFiles";
+			File file = new File(file_path);
+			if (!file.exists()) {
+				file.mkdirs();
 			}
-		}else {
-			album.setImagesPdf(albumDTO.getMargePdfUrls().get(0));
 		}
+		if (excelTab != null) {
+			//获取数据
+			try {
+					//需要删除的本地文件集合
+					List<String> removeList = new ArrayList<>();
+							//获取模板文件流
+							InputStream modInput = null;
+							FileInputStream excelFileInput = null;
+							FileOutputStream outputStream = null;
+							Workbook workbook = null;
 
+							List<String> pdfFileList = new ArrayList<>();
+							//两个图片一组
+							List<List<String>> groupUrls =  CommonUtil.getBatchSize(uris, 2);
+							for (List<String> urls : groupUrls) {
+								try {
+									//创建模板Workbook
+									modInput = CommonUtil.getOSSInputStream(excelTab.getFileUrl());
+									if (modInput != null) {
+										workbook = WorkbookFactory.create(modInput);
+										for (int i = 0, l = urls.size(); i < l; i++) {
+											try {
+												CreationHelper helper = workbook.getCreationHelper();
+												Sheet sheet = workbook.getSheetAt(0);
+												Drawing<?> drawing = sheet.createDrawingPatriarch();
+												ClientAnchor anchor = helper.createClientAnchor();
+												Long id = map.get(urls.get(i));
+								                ImageClassificationFile file=imageClassificationFileClient.getImageClassificationFileById(id);
+												//获取文件流
+												byte[] bytes = CommonUtil.InputStreamToBytes(CommonUtil.getOSSInputStream(urls.get(i)));
+												if (bytes[0] == 82 && bytes[1] == 73 && bytes[2] == 70){
+													bytes = CommonUtil.webpToPngBytes(CommonUtil.getOSSInputStream(urls.get(i)));
+												}
+												//压缩文件大小
+												byte[] byteNew = FileUtils.compressImage(bytes);
+												//创建图片
+												Picture picture = drawing.createPicture(anchor, workbook.addPicture(byteNew, Workbook.PICTURE_TYPE_PNG));
+												picture.resize();
+
+												//图片定位
+												FileUtils.imageOrientation(sheet, anchor, i == 1 ? new DataVO(1, 8) : new DataVO(0, 2));
+
+												//定位其它信息
+												//文字说明
+												sheet.getRow(i == 0 ? 0 : 6).getCell(i == 0 ? 3 : 0).setCellValue("文字说明:\n" + "  " + (ObjectUtil.isNotEmpty(file.getTextContent()) ? file.getTextContent() : ""));
+												//照片号
+												sheet.getRow(i == 0 ? 1 : 7).getCell(i == 0 ? 3 : 0).setCellValue("照片号:\n" + "  " + (ObjectUtil.isNotEmpty(file.getPhotoCode()) ? file.getPhotoCode() : ""));
+												//底片号
+												sheet.getRow(i == 0 ? 2 : 8).getCell(i == 0 ? 3 : 0).setCellValue("底片号:\n" + "  " + (ObjectUtil.isNotEmpty(file.getFilmCode()) ? file.getFilmCode() : ""));
+												//题名
+												sheet.getRow(i == 0 ? 3 : 9).getCell(i == 0 ? 0 : 2).setCellValue("题名:\n" + "  " + (ObjectUtil.isNotEmpty(file.getTitle()) ? file.getTitle() : ""));
+												//参见号
+												sheet.getRow(i == 0 ? 3 : 9).getCell(i == 0 ? 2 : 0).setCellValue("参见号:\n" + "  " + (ObjectUtil.isNotEmpty(file.getSeeAlsoCode()) ? file.getSeeAlsoCode() : ""));
+												//拍摄时间
+												sheet.getRow(i == 0 ? 4 : 10).getCell(i == 0 ? 2 : 0).setCellValue("拍摄时间:\n" + "  " + (ObjectUtil.isNotEmpty(DateUtil.format(file.getShootingTime(), "yyyy-MM-dd")) ? DateUtil.format(file.getShootingTime(), "yyyy-MM-dd") : ""));
+												//拍摄者
+												sheet.getRow(i == 0 ? 5 : 11).getCell(i == 0 ? 2 : 0).setCellValue("拍摄者:\n" + "  " + (ObjectUtil.isNotEmpty(file.getShootingUser()) ? file.getShootingUser() : ""));
+
+											} catch (Exception e) {
+												e.printStackTrace();
+											}
+										}
+
+										String locationFile = file_path + SnowFlakeUtil.getId() + ".xlsx";
+										outputStream = new FileOutputStream(locationFile);
+										//记录文件删除
+										removeList.add(locationFile);
+										//生成一份新的excel
+										workbook.write(outputStream);
+										//将excel转PDF
+										File excelFile = new File(locationFile);
+										excelFileInput = new FileInputStream(excelFile);
+										MultipartFile files = new MockMultipartFile("file", excelFile.getName(), "text/plain", IOUtils.toByteArray(excelFileInput));
+										NewBladeFile bladeFile = this.commonFileClient.excelToPdf(files);
+										if (bladeFile != null) {
+											pdfFileList.add(bladeFile.getPdfUrl());
+										}
+									}
+								} catch (Exception e) {
+									e.printStackTrace();
+								} finally {
+									if (outputStream != null) {
+										IoUtil.closeQuietly(outputStream);
+									}
+									if (modInput != null) {
+										IoUtil.closeQuietly(modInput);
+									}
+									if (excelFileInput != null) {
+										IoUtil.closeQuietly(excelFileInput);
+									}
+									if (workbook != null) {
+										IoUtil.closeQuietly(workbook);
+									}
+								}
+							}
+
+							//合并pdf并上传
+							String mergeName = SnowFlakeUtil.getId() + ".pdf";
+							String mergeUrl = file_path + mergeName;
+							FileUtils.mergePdfPublicMethods(pdfFileList, mergeUrl);
+							//记录文件删除
+							removeList.add(mergeUrl);
+							//上传
+							BladeFile bladeFile = this.newIOSSClient.uploadFile(mergeName, mergeUrl);
+							if (bladeFile != null) {
+								album.setImagesPdf(bladeFile.getLink());
+							}
+
+					if (removeList.size() > 0) {
+						//删除本地文件
+						CommonUtil.removeFile(removeList);
+					}
+
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
 		return R.status(albumService.save(album));
 	}
 

+ 88 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/FileUtils.java

@@ -3,6 +3,11 @@ package org.springblade.manager.utils;
 import com.aspose.cells.PdfSaveOptions;
 import com.aspose.cells.SaveFormat;
 import com.aspose.cells.Workbook;
+import com.drew.imaging.ImageMetadataReader;
+import com.drew.imaging.ImageProcessingException;
+import com.drew.metadata.Metadata;
+import com.drew.metadata.MetadataException;
+import com.drew.metadata.exif.ExifIFD0Directory;
 import com.itextpdf.io.image.ImageType;
 import com.itextpdf.text.Document;
 import com.itextpdf.text.pdf.PdfCopy;
@@ -36,9 +41,14 @@ import org.springblade.core.tool.utils.ResourceUtil;
 import org.springblade.system.cache.ParamCache;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.imageio.IIOImage;
 import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
 import javax.servlet.http.HttpServletResponse;
 import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.net.URLEncoder;
@@ -121,6 +131,84 @@ public class FileUtils {
         }
     }
 
+
+    public static byte[] compressImage(byte[] imageData) throws IOException, ImageProcessingException, MetadataException {
+        // 读取原始图像(处理旋转问题)
+        Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
+        if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
+            ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
+            if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
+                // 获取 Orientation 标签的值
+                int orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
+                // 需要旋转图片
+                BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageData));
+                AffineTransform transform = new AffineTransform();
+                if (orientation == 6) {
+                    transform.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
+                } else if (orientation == 8) {
+                    transform.rotate(-Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
+                }
+                AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
+                originalImage = op.filter(originalImage, null);
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                ImageIO.write(originalImage, "jpg", baos);
+                imageData = baos.toByteArray();
+            }
+        }
+        // 缩放图像
+        String formatName = "JPEG";
+        ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
+        BufferedImage originalImage = ImageIO.read(bais);
+        long sizeLimit = 366912; //358KB
+        int width = 768;
+        int height = 1024;
+        Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
+
+        // 压缩图像
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ImageIO.write(resizedImage, formatName, baos);
+
+        if (baos.size() <= sizeLimit) {
+            // 图片大小已经小于等于目标大小,直接返回原始数据
+            return baos.toByteArray();
+        }
+
+        float quality = 0.9f; // 初始化压缩质量
+        int retries = 10; // 最多尝试 10 次
+
+        while (baos.size() > sizeLimit && retries > 0) {
+            // 压缩图像并重新计算压缩质量
+            byte[] data = baos.toByteArray();
+            bais = new ByteArrayInputStream(data);
+            BufferedImage compressedImage = ImageIO.read(bais);
+            baos.reset();
+
+            ImageWriter writer = null;
+            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
+            if (writers.hasNext()) {
+                writer = writers.next();
+            } else {
+                throw new IllegalArgumentException("Unsupported image format: " + formatName);
+            }
+
+            ImageWriteParam writeParam = writer.getDefaultWriteParam();
+            writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+            writeParam.setCompressionQuality(quality);
+
+            writer.setOutput(ImageIO.createImageOutputStream(baos));
+            writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
+            writer.dispose();
+
+            float ratio = sizeLimit * 1.0f / baos.size();
+            quality *= Math.sqrt(ratio);
+            retries--;
+        }
+
+        return baos.toByteArray();
+    }
+
     /**
      * 图片定位
      */

+ 64 - 0
blade-service/blade-user/src/main/java/org/springblade/system/user/controller/UserController.java

@@ -751,4 +751,68 @@ public class UserController {
         }
         return this.getLoginInfo(Authorization, userInfo);
     }
+
+
+    /**
+     * 项目内部获取用户接口
+     * @param account
+     * @param type
+     * @param tenantId
+     * @param request
+     * @return
+     */
+    @PostMapping("/loginByToken4")
+    @ApiOperationSupport(order = 20)
+    @ApiOperation(value = "token验证加密", notes = "token验证登录")
+    public R loginByToken4(String account,Integer type, String tenantId, HttpServletRequest request) {
+        if(account==null || Func.isNull(account) || Func.isEmpty(account)){
+            return R.fail("account值不能为空");
+        }
+        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("account", account);
+        queryWrapper.eq("sys_type", type == null ? 2 : type);
+        if(StringUtil.isNotBlank(tenantId)){
+            queryWrapper.eq("tenant_id", tenantId);
+        }
+        queryWrapper.last("limit 1");
+        User userInfo = userService.getOne(queryWrapper);
+        if (userInfo == null) {
+            return R.fail("用户名或密码错误");
+        }
+
+        String Authorization = request == null ? null : request.getHeader("Authorization");
+
+        if (Authorization == null || StringUtil.isEmpty(Authorization)) {
+            String useType = userInfo.getUserType();
+            List<String> strList = Func.toStrList(useType);
+            for(String sys_id:strList){
+                String dataInfo = "";
+                if(sys_id.equals("1")){ //质量/试验平台
+                    dataInfo ="client:client_secret";
+                }else if(sys_id.equals("2")){ //APP端
+                    dataInfo ="uni-app:app_secret";
+                }else if(sys_id.equals("3")){ //档案平台"
+                    dataInfo ="archives:archives_secret";
+                }else if(sys_id.equals("4")){ //后台管理端"
+                    dataInfo ="saber:saber_secret";
+                }else if(sys_id.equals("5")){ //成本管控系统"
+                    dataInfo ="hac:hac_secret";
+                }else if(sys_id.equals("6")){ //征拆系统"
+                    dataInfo ="lar:lar_secret";
+                }else if(sys_id.equals("7")){ //计量系统"
+                    dataInfo ="measure:measure_secret";
+                }else if(sys_id.equals("8")){ //安全系统"
+                    dataInfo ="measure:measure_secret";
+                }
+                Authorization = "Basic "+Func.encodeBase64(dataInfo);
+                //Basic bWVhc3VyZTptZWFzdXJlX3NlY3JldA==
+                //Basic bWVhc3VyZTptZWFzdXJlX3NlY3JldA==
+                R loginInfo = this.getLoginInfo(Authorization, userInfo);
+                if(loginInfo.getCode()==200){
+                    return loginInfo;
+                }
+            }
+        }
+        return this.getLoginInfo(Authorization,userInfo);
+    }
 }

+ 14 - 0
blade-service/blade-user/src/main/java/org/springblade/system/user/feign/UserClient.java

@@ -16,12 +16,15 @@
  */
 package org.springblade.system.user.feign;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.AllArgsConstructor;
 import org.springblade.core.tenant.annotation.NonDS;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.dto.SaveUserInfoByProjectDTO;
+import org.springblade.system.user.bean.ResultCYData;
+import org.springblade.system.user.controller.UserController;
 import org.springblade.system.user.dto.UserDTO;
 import org.springblade.system.user.entity.User;
 import org.springblade.system.user.entity.UserInfo;
@@ -46,6 +49,7 @@ import java.util.List;
 public class UserClient implements IUserClient {
 
     private final IUserService service;
+    private final UserController userController;
 
     @Override
     public List<User> findUserInfoList() {
@@ -149,5 +153,15 @@ public class UserClient implements IUserClient {
         service.clearContractLocalCacheAndRedisCache();
     }
 
+    @Override
+    public String getTokenByUser(String account) {
+        R r = userController.loginByToken4(account, 1,"000000",null);
+        if(r.isSuccess()){
+            JSONObject data = (JSONObject) r.getData();
+            return (String) data.get("access_token");
+        } else {
 
+            return null;
+        }
+    }
 }