Commit 54918760 authored by hongguangwu's avatar hongguangwu

1.7.24 - 派单审核时,抓取身份证、合同信息

parent 66b875b5
package com.yifu.cloud.plus.v1.yifu.archives.vo; import lombok.Data; import java.io.Serializable; /** * 人员档案身份证正反面附件信息 */ @Data public class IdCardAttaVo implements Serializable { // 员工id private String empId; // 员工身份证正面图片 private String frontAttaSrc; private String frontAttaName; // 员工身份证反面图片 private String backAttaSrc; private String backAttaName; // 员工合同pdf private String contractAttaSrc; private String contractAttaName; }
\ No newline at end of file
package com.yifu.cloud.plus.v1.yifu.archives.vo; import lombok.Data; import java.io.Serializable; /** * 查询人员档案身份证附件入参 */ @Data public class IdCardQueryVo implements Serializable { private String empId; private String empIdcard; private String deptNo; }
\ No newline at end of file
...@@ -455,4 +455,13 @@ public class TEmployeeContractInfoController { ...@@ -455,4 +455,13 @@ public class TEmployeeContractInfoController {
return tEmployeeContractInfoService.selectExitEmpCopntractNew(cardVo); return tEmployeeContractInfoService.selectExitEmpCopntractNew(cardVo);
} }
/**
* 内部接口:获取合同pdf OSS 信息
*/
@Inner
@PostMapping("/inner/getContractAttaByEmpIdCard")
public IdCardAttaVo getIdCardAttaByEmpIdCard(@RequestBody IdCardQueryVo queryVo) {
return tEmployeeContractInfoService.getContractAttaByEmpIdCard(queryVo);
}
} }
...@@ -187,6 +187,15 @@ public class TEmployeeInfoController { ...@@ -187,6 +187,15 @@ public class TEmployeeInfoController {
return tEmployeeInfoService.getInfoByIdcard(idcard); return tEmployeeInfoService.getInfoByIdcard(idcard);
} }
/**
* 内部接口:获取人员档案身份证正反面 OSS 信息
*/
@Inner
@PostMapping("/inner/getIdCardAttaByEmpIdCard")
public IdCardAttaVo getIdCardAttaByEmpIdCard(@RequestBody IdCardQueryVo queryVo) {
return tEmployeeInfoService.getIdCardAttaByEmpIdCard(queryVo);
}
/** /**
* @param empName 姓名 * @param empName 姓名
* @param empIdCard 身份证 * @param empIdCard 身份证
......
...@@ -115,6 +115,8 @@ public interface TEmployeeContractInfoMapper extends BaseMapper<TEmployeeContrac ...@@ -115,6 +115,8 @@ public interface TEmployeeContractInfoMapper extends BaseMapper<TEmployeeContrac
String getContractByEmpIdCardAndDeptId(@Param("empIdCard") String empIdCard, @Param("deptId") String deptId); String getContractByEmpIdCardAndDeptId(@Param("empIdCard") String empIdCard, @Param("deptId") String deptId);
String getContractByEmpIdCardAndDeptNo(@Param("empIdCard") String empIdCard, @Param("deptNo") String deptNo); String getContractByEmpIdCardAndDeptNo(@Param("empIdCard") String empIdCard, @Param("deptNo") String deptNo);
/* 查询合同id,用来获取附件-派单审核用的 */
String getContractForFile(@Param("empIdCard") String empIdCard, @Param("deptNo") String deptNo);
String getContractByEmpIdCardAndDeptNoByEnd(@Param("empIdCard") String empIdCard, @Param("deptNo") String deptNo); String getContractByEmpIdCardAndDeptNoByEnd(@Param("empIdCard") String empIdCard, @Param("deptNo") String deptNo);
String getMinDateByCardAndDeptId(@Param("vo") IdNameNoVo vo); String getMinDateByCardAndDeptId(@Param("vo") IdNameNoVo vo);
......
...@@ -209,4 +209,9 @@ public interface TEmployeeContractInfoService extends IService<TEmployeeContract ...@@ -209,4 +209,9 @@ public interface TEmployeeContractInfoService extends IService<TEmployeeContract
// 查找最近的终止合同 // 查找最近的终止合同
String getContractByEmpIdCardAndDeptNoByEnd(String empIdCard, String deptNo); String getContractByEmpIdCardAndDeptNoByEnd(String empIdCard, String deptNo);
/**
* 获取合同pdf OSS 信息
*/
IdCardAttaVo getContractAttaByEmpIdCard(IdCardQueryVo queryVo);
} }
...@@ -306,4 +306,9 @@ public interface TEmployeeInfoService extends IService<TEmployeeInfo> { ...@@ -306,4 +306,9 @@ public interface TEmployeeInfoService extends IService<TEmployeeInfo> {
BaseSearchVO getEmpAndContractStatus(BaseSearchVO paramVo); BaseSearchVO getEmpAndContractStatus(BaseSearchVO paramVo);
/**
* 获取人员档案身份证正反面附件 OSS 信息
*/
IdCardAttaVo getIdCardAttaByEmpIdCard(IdCardQueryVo queryVo);
} }
...@@ -2793,4 +2793,29 @@ public class TEmployeeContractInfoServiceImpl extends ServiceImpl<TEmployeeContr ...@@ -2793,4 +2793,29 @@ public class TEmployeeContractInfoServiceImpl extends ServiceImpl<TEmployeeContr
null,null); null,null);
} }
@Override
public IdCardAttaVo getContractAttaByEmpIdCard(IdCardQueryVo queryVo) {
IdCardAttaVo vo = new IdCardAttaVo();
if (queryVo == null) {
return vo;
}
String doMainId = null;
if (Common.isNotNull(queryVo.getEmpIdcard())) {
doMainId = baseMapper.getContractForFile(queryVo.getEmpIdcard(), queryVo.getDeptNo());
}
if (Common.isEmpty(doMainId)) {
return vo;
}
TAttaInfo attaInfo = tAttaInfoService.getOne(Wrappers.<TAttaInfo>query().lambda()
.eq(TAttaInfo::getDomainId,doMainId)
.eq(TAttaInfo::getRelationType, CommonConstants.FOUR_STRING)
.orderByDesc(TAttaInfo::getCreateTime)
.last(CommonConstants.LAST_ONE_SQL));
if (Common.isNotNull(attaInfo) && Common.isNotNull(attaInfo.getAttaSrc())) {
vo.setContractAttaSrc(attaInfo.getAttaSrc());
vo.setContractAttaName(attaInfo.getAttaName());
}
return vo;
}
} }
...@@ -2859,6 +2859,41 @@ public class TEmployeeInfoServiceImpl extends ServiceImpl<TEmployeeInfoMapper, T ...@@ -2859,6 +2859,41 @@ public class TEmployeeInfoServiceImpl extends ServiceImpl<TEmployeeInfoMapper, T
.last(CommonConstants.LAST_ONE_SQL)); .last(CommonConstants.LAST_ONE_SQL));
} }
@Override
public IdCardAttaVo getIdCardAttaByEmpIdCard(IdCardQueryVo queryVo) {
IdCardAttaVo vo = new IdCardAttaVo();
if (queryVo == null) {
return vo;
}
String empId = null;
if (Common.isNotNull(queryVo.getEmpIdcard())) {
TEmployeeInfo emp = getInfoByIdcard(queryVo.getEmpIdcard());
if (emp != null) {
empId = emp.getId();
}
}
if (Common.isEmpty(empId)) {
return vo;
}
vo.setEmpId(empId);
List<TAttaInfo> attaList = attaInfoService.list(Wrappers.<TAttaInfo>query().lambda()
.eq(TAttaInfo::getDomainId, empId)
.in(TAttaInfo::getRelationType, "9", "24")
.orderByDesc(TAttaInfo::getCreateTime));
if (Common.isNotNull(attaList)) {
for (TAttaInfo atta : attaList) {
if ("9".equals(atta.getRelationType()) && Common.isEmpty(vo.getFrontAttaSrc())) {
vo.setFrontAttaSrc(atta.getAttaSrc());
vo.setFrontAttaName(atta.getAttaName());
} else if ("24".equals(atta.getRelationType()) && Common.isEmpty(vo.getBackAttaSrc())) {
vo.setBackAttaSrc(atta.getAttaSrc());
vo.setBackAttaName(atta.getAttaName());
}
}
}
return vo;
}
@Override @Override
public TEmployeeInfo getTEmployeeInfoByIdcardAndName(IdNameNoVo vo) { public TEmployeeInfo getTEmployeeInfoByIdcardAndName(IdNameNoVo vo) {
return baseMapper.selectOne(Wrappers.<TEmployeeInfo>query().lambda() return baseMapper.selectOne(Wrappers.<TEmployeeInfo>query().lambda()
......
...@@ -940,4 +940,15 @@ ...@@ -940,4 +940,15 @@
</where> </where>
</select> </select>
<!-- 查询合同id,用来获取附件 -->
<select id="getContractForFile" resultType="java.lang.String">
select
e.id
from t_employee_contract_info e
where e.EMP_IDCARD = #{empIdCard} and e.DEPT_NO = #{deptNo}
and e.DELETE_FLAG = '0'
AND e.IN_USE = '0' and e.TYPE='5' and e.IS_FILE = '0'
limit 1
</select>
</mapper> </mapper>
...@@ -262,6 +262,39 @@ public class ArchivesDaprUtil { ...@@ -262,6 +262,39 @@ public class ArchivesDaprUtil {
return res; return res;
} }
/**
* 获取人员档案身份证正反面 OSS 信息
*/
public R<IdCardAttaVo> getIdCardAttaByEmpIdCard(String empIdcard) {
IdCardQueryVo queryVo = new IdCardQueryVo();
queryVo.setEmpIdcard(empIdcard);
R<IdCardAttaVo> res = HttpDaprUtil.invokeMethodPost(
daprArchivesProperties.getAppUrl(), daprArchivesProperties.getAppId(),
"/temployeeinfo/inner/getIdCardAttaByEmpIdCard", JSON.toJSONString(queryVo),
IdCardAttaVo.class, SecurityConstants.FROM_IN);
if (Common.isEmpty(res)) {
return R.failed("获取档案身份证信息失败!");
}
return res;
}
/**
* 获取人员合同 OSS 信息
*/
public R<IdCardAttaVo> getContractAttaByEmpIdCard(String empIdcard, String deptNo) {
IdCardQueryVo queryVo = new IdCardQueryVo();
queryVo.setEmpIdcard(empIdcard);
queryVo.setDeptNo(deptNo);
R<IdCardAttaVo> res = HttpDaprUtil.invokeMethodPost(
daprArchivesProperties.getAppUrl(), daprArchivesProperties.getAppId(),
"/temployeecontractinfo/inner/getContractAttaByEmpIdCard", JSON.toJSONString(queryVo),
IdCardAttaVo.class, SecurityConstants.FROM_IN);
if (Common.isEmpty(res)) {
return R.failed("获取合同附件信息失败!");
}
return res;
}
/** /**
* @param vo * @param vo
* @Description: 获取档案基本信息 * @Description: 获取档案基本信息
......
...@@ -204,7 +204,28 @@ public class DispatchConstants { ...@@ -204,7 +204,28 @@ public class DispatchConstants {
public static final String EMPLOYEE= "员工:"; public static final String EMPLOYEE= "员工:";
/** 社保-档案身份证合成图 */
public static final String ATTA_TYPE_ID_CARD_MERGE_YGS = "15";
/** 医保-档案身份证合成图 */
public static final String ATTA_TYPE_ID_CARD_MERGE_YSD = "16";
/** 社保-档案合同合成图(预留) */
public static final String ATTA_TYPE_CONTRACT_MERGE_YGS = "17";
/** 医保-档案合同合成图(预留) */
public static final String ATTA_TYPE_CONTRACT_MERGE_YSD = "18";
public static final String MSG_NO_ID_CARD = "档案无身份证信息";
// 审核类型:自动化派单-无需审核
// 归档状态:已归档
// 合同状态:可用。
// 身份证+ 项目编码。
// 获取pdf类型的合同,转化为图片,压缩4M以下。
public static final String MSG_NO_CONTRACT = "档案无合同附件";
public static final String MSG_MERGE_FAILED = "合成失败";
} }
...@@ -59,10 +59,11 @@ public class TAttaInfo extends BaseEntity { ...@@ -59,10 +59,11 @@ public class TAttaInfo extends BaseEntity {
/** /**
* 1户配置的章;2:派单审核附件,税友单个使用,社保3医保附件;11社保增花名册模板;12社保减花名册模板;13医保增花名册模板;14医保减花名册模板 * 1户配置的章;2:派单审核附件,税友单个使用,社保3医保附件;11社保增花名册模板;12社保减花名册模板;13医保增花名册模板;14医保减花名册模板
* 4:单个附件_社保_花名册;5:单个附件_医保_花名册;6:单个附件_解除劳动合同证明书(1.7.22版本) * 4:单个附件_社保_花名册;5:单个附件_医保_花名册;6:单个附件_解除劳动合同证明书(1.7.22版本)
* 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图
*/ */
@NotBlank(message = "关系类型不能为空") @NotBlank(message = "关系类型不能为空")
@Length(max = 2, message = "关系类型不能超过2个字符") @Length(max = 2, message = "关系类型不能超过2个字符")
@Schema(description = "关系类型(1户配置的章;2:派单审核附件,税友单个使用,社保;3医保附件;4:单个附件_社保_花名册;5:单个附件_医保_花名册;6:单个附件_解除劳动合同证明书;11社保增花名册模板;12社保减花名册模板;13医保增花名册模板;14医保减花名册模板)") @Schema(description = "关系类型(1户配置的章;2:派单审核附件,税友单个使用,社保;3医保附件;4:单个附件_社保_花名册;5:单个附件_医保_花名册;6:单个附件_解除劳动合同证明书;15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图;11社保增花名册模板;12社保减花名册模板;13医保增花名册模板;14医保减花名册模板)")
private String relationType; private String relationType;
/** /**
* 实体id和关系类型共同确定附件所属(9、10、21、22、23、24、25存项目档案id,0、2、26存附属表id) * 实体id和关系类型共同确定附件所属(9、10、21、22、23、24、25存项目档案id,0、2、26存附属表id)
......
...@@ -122,6 +122,11 @@ ...@@ -122,6 +122,11 @@
<artifactId>aspose-cells</artifactId> <artifactId>aspose-cells</artifactId>
<version>23.1</version> <version>23.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.29</version>
</dependency>
</dependencies> </dependencies>
......
...@@ -171,6 +171,7 @@ public class FileUploadController { ...@@ -171,6 +171,7 @@ public class FileUploadController {
* @param domainId 关联id * @param domainId 关联id
* @param type 类型 1户配置的章;2:派单审核附件,税友单个使用,社保3医保附件;11社保增花名册模板;12社保减花名册模板;13医保增花名册模板;14医保减花名册模板 * @param type 类型 1户配置的章;2:派单审核附件,税友单个使用,社保3医保附件;11社保增花名册模板;12社保减花名册模板;13医保增花名册模板;14医保减花名册模板
* 4:单个附件_社保_花名册;5:单个附件_医保_花名册;6:单个附件_解除劳动合同证明书(1.7.22版本) * 4:单个附件_社保_花名册;5:单个附件_医保_花名册;6:单个附件_解除劳动合同证明书(1.7.22版本)
* 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图
* @Description: 获取社保服务的附件信息 * @Description: 获取社保服务的附件信息
* @Author: hgw * @Author: hgw
* @Date: 2025/4/28 14:12 * @Date: 2025/4/28 14:12
......
...@@ -38,6 +38,8 @@ import com.yifu.cloud.plus.v1.yifu.common.log.annotation.SysLog; ...@@ -38,6 +38,8 @@ import com.yifu.cloud.plus.v1.yifu.common.log.annotation.SysLog;
import com.yifu.cloud.plus.v1.yifu.common.security.annotation.Inner; import com.yifu.cloud.plus.v1.yifu.common.security.annotation.Inner;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils; import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import com.yifu.cloud.plus.v1.yifu.social.entity.TDispatchInfo; import com.yifu.cloud.plus.v1.yifu.social.entity.TDispatchInfo;
import com.yifu.cloud.plus.v1.yifu.social.entity.TAttaInfo;
import com.yifu.cloud.plus.v1.yifu.social.service.DispatchIdCardService;
import com.yifu.cloud.plus.v1.yifu.social.service.TDispatchInfoService; import com.yifu.cloud.plus.v1.yifu.social.service.TDispatchInfoService;
import com.yifu.cloud.plus.v1.yifu.social.util.DoSocialTask; import com.yifu.cloud.plus.v1.yifu.social.util.DoSocialTask;
import com.yifu.cloud.plus.v1.yifu.social.vo.*; import com.yifu.cloud.plus.v1.yifu.social.vo.*;
...@@ -72,6 +74,8 @@ public class TDispatchInfoController { ...@@ -72,6 +74,8 @@ public class TDispatchInfoController {
private final TDispatchInfoService tDispatchInfoService; private final TDispatchInfoService tDispatchInfoService;
private final DispatchIdCardService dispatchIdCardService;
private final MenuUtil menuUtil; private final MenuUtil menuUtil;
private final DaprArchivesProperties daprArchivesProperties; private final DaprArchivesProperties daprArchivesProperties;
...@@ -551,6 +555,18 @@ public class TDispatchInfoController { ...@@ -551,6 +555,18 @@ public class TDispatchInfoController {
return tDispatchInfoService.leaveToReduceSocialAndFund(paramVo); return tDispatchInfoService.leaveToReduceSocialAndFund(paramVo);
} }
/**
* 派单审核前:从档案抓取身份证正反面,合成 PNG 并上传至派单附件
* relationType 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图
*/
@Operation(description = "派单审核前抓取档案身份证、合同归档附件合成上传,relationType 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图")
@SysLog("派单抓取档案身份证、合同归档附件合成上传")
@GetMapping("/generateIdCardImage")
public R<TAttaInfo> generateIdCardImage(@RequestParam String dispatchId,
@RequestParam String relationType) {
return dispatchIdCardService.generateIdCardImage(dispatchId, relationType);
}
/** /**
* @Author fxj * @Author fxj
* @Description 派单申请批量审核 * @Description 派单申请批量审核
......
package com.yifu.cloud.plus.v1.yifu.social.service;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.social.entity.TAttaInfo;
/**
* 派单身份证合成附件服务
*/
public interface DispatchIdCardService {
/**
* 从档案抓取身份证正反面,合成 PNG 并上传至派单附件
*
* @param dispatchId 派单ID
* @param relationType 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图
*/
R<TAttaInfo> generateIdCardImage(String dispatchId, String relationType);
}
package com.yifu.cloud.plus.v1.yifu.social.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yifu.cloud.plus.v1.yifu.archives.vo.IdCardAttaVo;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.OSSUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.ArchivesDaprUtil;
import com.yifu.cloud.plus.v1.yifu.social.constants.DispatchConstants;
import com.yifu.cloud.plus.v1.yifu.social.entity.TAttaInfo;
import com.yifu.cloud.plus.v1.yifu.social.entity.TDispatchInfo;
import com.yifu.cloud.plus.v1.yifu.social.service.DispatchIdCardService;
import com.yifu.cloud.plus.v1.yifu.social.service.TAttaInfoService;
import com.yifu.cloud.plus.v1.yifu.social.service.TDispatchInfoService;
import com.yifu.cloud.plus.v1.yifu.social.util.ContractPdfUtil;
import com.yifu.cloud.plus.v1.yifu.social.util.IdCardMergeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.List;
/**
* 派单身份证合成附件服务实现
*/
@Log4j2
@Service
@RequiredArgsConstructor
public class DispatchIdCardServiceImpl implements DispatchIdCardService {
private final TDispatchInfoService tDispatchInfoService;
private final ArchivesDaprUtil archivesDaprUtil;
private final OSSUtil ossUtil;
private final TAttaInfoService tAttaInfoService;
// 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图
private static final String S_15 = "15";
private static final String S_16 = "16";
private static final String S_17 = "17";
private static final String S_18 = "18";
// relationType 15:社保-档案身份证合成图;16:医保-档案身份证合成图;17:社保-档案合同合成图;18:医保-档案合同合成图
@Override
public R<TAttaInfo> generateIdCardImage(String dispatchId, String relationType) {
if (Common.isEmpty(dispatchId) || Common.isEmpty(relationType)) {
return R.failed(CommonConstants.PARAM_IS_NOT_ERROR);
}
if (!S_15.equals(relationType) && !S_16.equals(relationType) && !S_17.equals(relationType) && !S_18.equals(relationType)) {
return R.failed("relationType错误,你传的是:" + relationType);
}
try {
TDispatchInfo dispatch = tDispatchInfoService.getById(dispatchId);
if (dispatch == null) {
return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
}
String fileName = dispatch.getEmpName() + "_身份证合成.png";
if (S_17.equals(relationType) || S_18.equals(relationType)) {
fileName = dispatch.getEmpName() + "_合同转化.png";
}
TAttaInfo attaInfo = getExistingAtta(dispatchId, relationType);
// 存在直接返回
// 策略1:当前派单,如果已有对应的生成图片,不会再次新生成,需要手动删除后,再次打开审核界面,才会再次拉取生成。
if (attaInfo != null && Common.isNotNull(attaInfo.getAttaSrc())) {
URL url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
if (url != null) {
attaInfo.setAttaUrl(url.toString());
}
return R.ok(attaInfo);
} else {
// 策略2:社保、医保的身份证,是同一个,如果社保有,医保就复制,不抓取生成,医保有,社保没有,也是复制。
//合同同理。
String otherRelationType;
switch (relationType) {
case S_15:
otherRelationType = S_16;
break;
case S_16:
otherRelationType = S_15;
break;
case S_17:
otherRelationType = S_18;
break;
default:
otherRelationType = S_17;
break;
}
TAttaInfo otherAttaInfo = getExistingAtta(dispatchId, otherRelationType);
if (otherAttaInfo != null && Common.isNotNull(otherAttaInfo.getAttaSrc())) {
attaInfo = buildAttaInfo(fileName, otherAttaInfo.getAttaSrc(), otherAttaInfo.getAttaSize(), relationType, dispatchId);
attaInfo = tAttaInfoService.add(attaInfo);
URL url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
if (url != null) {
attaInfo.setAttaUrl(url.toString());
}
return R.ok(attaInfo);
}
}
if (S_15.equals(relationType) || S_16.equals(relationType)) {
// 身份证
return getCardAttaInfoR(dispatchId, relationType, dispatch, fileName);
} else {
// 合同
return getContractAttaInfoR(dispatchId, relationType, dispatch, fileName);
}
} catch (Exception e) {
log.error("派单身份证或合同合成失败, dispatchId={}, relationType={}", dispatchId, relationType, e);
return R.failed(DispatchConstants.MSG_MERGE_FAILED);
}
}
// 获取合同图片:
// 审核类型:自动化派单-无需审核
// 归档状态:已归档
// 合同状态:可用。
// 身份证+ 项目编码。
// 获取pdf类型的合同,转化为图片,压缩4M以下。
private R<TAttaInfo> getContractAttaInfoR(String dispatchId, String relationType, TDispatchInfo dispatch, String fileName) throws Exception {
TAttaInfo attaInfo;
IdCardAttaVo contractAtta = fetchContractAtta(dispatch);
if (contractAtta == null
|| Common.isEmpty(contractAtta.getContractAttaSrc())
|| Common.isEmpty(contractAtta.getContractAttaName())) {
return R.failed(DispatchConstants.MSG_NO_CONTRACT);
}
byte[] contractBytes = downloadOssObject(contractAtta.getContractAttaSrc());
byte[] mergedBytes = ContractPdfUtil.convertAllPagesAndCompress(contractBytes);
String key = "dispatch/contract/" + dispatchId + "/" + System.currentTimeMillis() + "_contract.png";
boolean uploaded = ossUtil.uploadFileByStream(new ByteArrayInputStream(mergedBytes), key, null);
if (!uploaded) {
return R.failed(DispatchConstants.MSG_MERGE_FAILED);
}
attaInfo = buildAttaInfo(fileName, key, mergedBytes.length, relationType, dispatchId);
attaInfo = tAttaInfoService.add(attaInfo);
URL url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
if (url != null) {
attaInfo.setAttaUrl(url.toString());
}
return R.ok(attaInfo);
}
// 获取身份证图片
private R<TAttaInfo> getCardAttaInfoR(String dispatchId, String relationType, TDispatchInfo dispatch, String fileName) throws Exception {
TAttaInfo attaInfo;
IdCardAttaVo idCardAtta = fetchIdCardAtta(dispatch);
if (idCardAtta == null
|| Common.isEmpty(idCardAtta.getFrontAttaSrc())
|| Common.isEmpty(idCardAtta.getBackAttaSrc())) {
return R.failed(DispatchConstants.MSG_NO_ID_CARD);
}
byte[] frontBytes = downloadOssObject(idCardAtta.getFrontAttaSrc());
byte[] backBytes = downloadOssObject(idCardAtta.getBackAttaSrc());
byte[] mergedBytes = IdCardMergeUtil.mergeAndCompress(frontBytes, backBytes);
String key = "dispatch/idCard/" + dispatchId + "/" + System.currentTimeMillis() + "_idcard.png";
boolean uploaded = ossUtil.uploadFileByStream(new ByteArrayInputStream(mergedBytes), key, null);
if (!uploaded) {
return R.failed(DispatchConstants.MSG_MERGE_FAILED);
}
attaInfo = buildAttaInfo(fileName, key, mergedBytes.length, relationType, dispatchId);
attaInfo = tAttaInfoService.add(attaInfo);
URL url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
if (url != null) {
attaInfo.setAttaUrl(url.toString());
}
return R.ok(attaInfo);
}
private IdCardAttaVo fetchIdCardAtta(TDispatchInfo dispatch) {
if (Common.isEmpty(dispatch.getEmpIdcard())) {
return null;
}
R<IdCardAttaVo> res = archivesDaprUtil.getIdCardAttaByEmpIdCard(dispatch.getEmpIdcard());
return res == null ? null : res.getData();
}
private IdCardAttaVo fetchContractAtta(TDispatchInfo dispatch) {
if (Common.isEmpty(dispatch.getEmpIdcard()) && Common.isEmpty(dispatch.getSettleDomainCode())) {
return null;
}
R<IdCardAttaVo> res = archivesDaprUtil.getContractAttaByEmpIdCard(dispatch.getEmpIdcard(), dispatch.getSettleDomainCode());
return res == null ? null : res.getData();
}
private byte[] downloadOssObject(String attaSrc) throws Exception {
URL url = ossUtil.getObjectUrl(null, attaSrc);
if (url == null) {
throw new IllegalStateException("oss url is null");
}
try (InputStream in = url.openStream()) {
return IOUtils.toByteArray(in);
}
}
private TAttaInfo getExistingAtta(String dispatchId, String relationType) {
List<TAttaInfo> oldList = tAttaInfoService.list(Wrappers.<TAttaInfo>query().lambda()
.eq(TAttaInfo::getDomainId, dispatchId)
.eq(TAttaInfo::getRelationType, relationType));
if (Common.isNotNull(oldList)) {
return oldList.get(0);
}
return null;
}
private TAttaInfo buildAttaInfo(String fileName, String key, long fileSize, String relationType, String dispatchId) {
TAttaInfo attaInfo = new TAttaInfo();
attaInfo.setAttaName(fileName);
attaInfo.setAttaSize(fileSize);
attaInfo.setAttaSrc(key);
attaInfo.setAttaType(".png");
attaInfo.setRelationType(relationType);
attaInfo.setDomainId(dispatchId);
attaInfo.setCreateTime(LocalDateTime.now());
return attaInfo;
}
}
...@@ -521,9 +521,13 @@ public class TSocialFriendPushServiceImpl extends ServiceImpl<TSocialFriendMappe ...@@ -521,9 +521,13 @@ public class TSocialFriendPushServiceImpl extends ServiceImpl<TSocialFriendMappe
imgUrl = socialFriendConfig.uploadPng(restTemplate, attaInfo.getAttaName(), base64String, backLog); imgUrl = socialFriendConfig.uploadPng(restTemplate, attaInfo.getAttaName(), base64String, backLog);
tSocialFriendBackLogService.save(backLog); tSocialFriendBackLogService.save(backLog);
if (Common.isNotNull(imgUrl)){ if (Common.isNotNull(imgUrl)){
if (Common.isEmpty(attaInfo.getRelationType()) || CommonConstants.TWO_STRING.equals(attaInfo.getRelationType())) { if (Common.isEmpty(attaInfo.getRelationType()) || CommonConstants.TWO_STRING.equals(attaInfo.getRelationType())
|| DispatchConstants.ATTA_TYPE_ID_CARD_MERGE_YGS.equals(attaInfo.getRelationType())
|| DispatchConstants.ATTA_TYPE_CONTRACT_MERGE_YGS.equals(attaInfo.getRelationType())) {
imgListYgs.add(imgUrl); imgListYgs.add(imgUrl);
} else if (CommonConstants.THREE_STRING.equals(attaInfo.getRelationType())) { } else if (CommonConstants.THREE_STRING.equals(attaInfo.getRelationType())
|| DispatchConstants.ATTA_TYPE_ID_CARD_MERGE_YSD.equals(attaInfo.getRelationType())
|| DispatchConstants.ATTA_TYPE_CONTRACT_MERGE_YSD.equals(attaInfo.getRelationType())) {
imgListYsd.add(imgUrl); imgListYsd.add(imgUrl);
}else if (CommonConstants.FOUR_STRING.equals(attaInfo.getRelationType()) && !isAutoYgsHmc) { }else if (CommonConstants.FOUR_STRING.equals(attaInfo.getRelationType()) && !isAutoYgsHmc) {
vo.setQyzgshbxzyhmc(imgUrl); vo.setQyzgshbxzyhmc(imgUrl);
......
package com.yifu.cloud.plus.v1.yifu.social.util;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 合同 PDF 全页转 PNG 并压缩
*/
public final class ContractPdfUtil {
private static final float PDF_RENDER_DPI_BASE = 150F;
private static float resolveRenderDpi(int pageCount) {
if (pageCount <= 3) {
return PDF_RENDER_DPI_BASE;
}
if (pageCount <= 8) {
return 120F;
}
if (pageCount <= 15) {
return 96F;
}
return 72F;
}
public static byte[] convertAllPagesAndCompress(byte[] pdfBytes) throws IOException {
if (pdfBytes == null || pdfBytes.length == 0) {
throw new IOException("pdf data is empty");
}
try (PDDocument document = PDDocument.load(new ByteArrayInputStream(pdfBytes))) {
int pageCount = document.getNumberOfPages();
if (pageCount <= 0) {
throw new IOException("pdf has no pages");
}
float dpi = resolveRenderDpi(pageCount);
PDFRenderer renderer = new PDFRenderer(document);
List<BufferedImage> pages = new ArrayList<>(pageCount);
for (int i = 0; i < pageCount; i++) {
pages.add(renderer.renderImageWithDPI(i, dpi, ImageType.RGB));
}
return IdCardMergeUtil.mergeVerticalAndCompress(pages);
}
}
}
package com.yifu.cloud.plus.v1.yifu.social.util;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* 图片纵向合成并压缩为 PNG
*/
public final class IdCardMergeUtil {
private static final long MAX_SIZE = 4L * 1024 * 1024;
/** 宽度下限,多页纵向合成时以宽度为缩放基准 */
private static final int MIN_WIDTH = 50;
private static final int MAX_COMPRESS_ATTEMPTS = 25;
private IdCardMergeUtil() {
}
public static byte[] mergeAndCompress(byte[] frontBytes, byte[] backBytes) throws IOException {
BufferedImage front = ImageIO.read(new ByteArrayInputStream(frontBytes));
BufferedImage back = ImageIO.read(new ByteArrayInputStream(backBytes));
if (front == null || back == null) {
throw new IOException("合成图片,但是没有图片数据");
}
return mergeVerticalAndCompress(Arrays.asList(front, back));
}
public static byte[] mergeVerticalAndCompress(List<BufferedImage> images) throws IOException {
if (images == null || images.isEmpty()) {
throw new IOException("合成身份证或转化合同图片,但是没有图片数据");
}
return compressToMaxSize(mergeVertical(images));
}
private static BufferedImage mergeVertical(List<BufferedImage> images) {
if (images.size() == 1) {
return images.get(0);
}
int targetWidth = 0;
int totalHeight = 0;
for (BufferedImage image : images) {
targetWidth = Math.max(targetWidth, image.getWidth());
}
List<BufferedImage> scaledImages = new java.util.ArrayList<>(images.size());
for (BufferedImage image : images) {
BufferedImage scaled = scaleToWidth(image, targetWidth);
scaledImages.add(scaled);
totalHeight += scaled.getHeight();
}
BufferedImage combined = new BufferedImage(targetWidth, totalHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = combined.createGraphics();
try {
g.setColor(Color.WHITE);
g.fillRect(0, 0, targetWidth, totalHeight);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
int y = 0;
for (BufferedImage scaled : scaledImages) {
g.drawImage(scaled, 0, y, null);
y += scaled.getHeight();
}
} finally {
g.dispose();
}
return combined;
}
private static BufferedImage scaleToWidth(BufferedImage image, int targetWidth) {
if (image.getWidth() == targetWidth) {
return image;
}
int targetHeight = (int) ((double) image.getHeight() / image.getWidth() * targetWidth);
BufferedImage scaled = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = scaled.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(image, 0, 0, targetWidth, targetHeight, null);
} finally {
g.dispose();
}
return scaled;
}
private static byte[] compressToMaxSize(BufferedImage image) throws IOException {
BufferedImage current = image;
for (int attempt = 0; attempt < MAX_COMPRESS_ATTEMPTS; attempt++) {
byte[] data = writePng(current);
if (data.length <= MAX_SIZE) {
return data;
}
if (current.getWidth() <= MIN_WIDTH) {
throw new IOException("压缩时,宽度小于60px后仍大于4MB,无法继续压缩,请检查原件");
}
double sizeRatio = (double) MAX_SIZE / data.length;
// PNG 体积与像素面积近似成正比,按面积比例开方估算缩放系数
double scale = Math.sqrt(sizeRatio) * 0.92D;
scale = Math.min(scale, 0.85D);
scale = Math.max(scale, 0.55D);
int newWidth = Math.max(MIN_WIDTH, (int) (current.getWidth() * scale));
int newHeight = Math.max(1, (int) (current.getHeight() * ((double) newWidth / current.getWidth())));
if (newWidth == current.getWidth() && newHeight == current.getHeight()) {
newWidth = Math.max(MIN_WIDTH, (int) (current.getWidth() * 0.85D));
newHeight = Math.max(1, (int) (current.getHeight() * 0.85D));
}
current = scaleImage(current, newWidth, newHeight);
}
throw new IOException("压缩时,宽度小于60px后仍大于4MB,无法继续压缩,请检查原件!");
}
private static byte[] writePng(BufferedImage image) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
return baos.toByteArray();
}
private static BufferedImage scaleImage(BufferedImage image, int newWidth, int newHeight) {
BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = resized.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(image, 0, 0, newWidth, newHeight, null);
} finally {
g.dispose();
}
return resized;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment