|
@@ -2,50 +2,41 @@ package org.jeecg.modules.app.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
-import com.google.gson.Gson;
|
|
|
-import com.google.gson.JsonArray;
|
|
|
-import com.google.gson.JsonElement;
|
|
|
-import com.google.gson.JsonObject;
|
|
|
+import com.google.gson.*;
|
|
|
+import com.google.gson.reflect.TypeToken;
|
|
|
import lombok.extern.log4j.Log4j2;
|
|
|
import org.apache.shiro.SecurityUtils;
|
|
|
import org.jeecg.common.exception.JeecgBootException;
|
|
|
import org.jeecg.common.system.vo.LoginUser;
|
|
|
import org.jeecg.modules.app.dto.DocTemplateDTO;
|
|
|
+import org.jeecg.modules.app.dto.ExternalAuthRequestDTO;
|
|
|
import org.jeecg.modules.app.dto.GetPsnAuthUrlDTO;
|
|
|
+import org.jeecg.modules.app.dto.SealInfoDTO;
|
|
|
import org.jeecg.modules.app.esign.comm.EsignHttpResponse;
|
|
|
import org.jeecg.modules.app.esign.exception.EsignDemoException;
|
|
|
import org.jeecg.modules.app.esign.fileAndTemplate.FileDemo;
|
|
|
import org.jeecg.modules.app.esign.sign.SignDemo;
|
|
|
import org.jeecg.modules.app.service.IESignService;
|
|
|
import org.jeecg.modules.system.app.dto.AppContractInfoDTO;
|
|
|
-import org.jeecg.modules.system.app.entity.AppContractInfo;
|
|
|
-import org.jeecg.modules.system.app.entity.AppContractSign;
|
|
|
-import org.jeecg.modules.system.app.entity.AppOrder;
|
|
|
-import org.jeecg.modules.system.app.entity.FamilyMembers;
|
|
|
-import org.jeecg.modules.system.app.mapper.AppContractInfoMapper;
|
|
|
-import org.jeecg.modules.system.app.mapper.AppContractSignMapper;
|
|
|
-import org.jeecg.modules.system.app.mapper.AppOrderMapper;
|
|
|
-import org.jeecg.modules.system.app.mapper.FamilyMembersMapper;
|
|
|
+import org.jeecg.modules.system.app.entity.*;
|
|
|
+import org.jeecg.modules.system.app.mapper.*;
|
|
|
import org.jeecg.modules.system.entity.SysDepart;
|
|
|
-import org.jeecg.modules.system.entity.SysUser;
|
|
|
import org.jeecg.modules.system.mapper.SysDepartMapper;
|
|
|
import org.jeecg.modules.system.mapper.SysUserMapper;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
-import java.io.File;
|
|
|
-import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
-import java.net.URL;
|
|
|
-import java.nio.file.Files;
|
|
|
-import java.nio.file.StandardCopyOption;
|
|
|
import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
import static com.alibaba.dashscope.utils.JsonUtils.gson;
|
|
|
import static org.jeecg.modules.app.esign.auth.ESignAuth.*;
|
|
|
import static org.jeecg.modules.app.esign.fileAndTemplate.TemplateDemo.getTemplateCreateUrl;
|
|
|
import static org.jeecg.modules.app.esign.fileAndTemplate.TemplateDemo.getTemplateEditUrl;
|
|
|
+import static org.jeecg.modules.app.esign.members.MembersDemo.administrators;
|
|
|
+import static org.jeecg.modules.app.esign.seal.SealDemo.orgOwnSealList;
|
|
|
+import static org.jeecg.modules.app.esign.seal.SealDemo.orgSealsExternalAuth;
|
|
|
import static org.jeecg.modules.app.esign.sign.SignDemo.createByFile;
|
|
|
|
|
|
@Service
|
|
@@ -63,6 +54,14 @@ public class ESignServiceImpl implements IESignService {
|
|
|
private AppContractSignMapper appContractSignMapper;
|
|
|
@Resource
|
|
|
private FamilyMembersMapper familyMembersMapper;
|
|
|
+ @Resource
|
|
|
+ private AppSiteMapper appSiteMapper;
|
|
|
+ private static final String NOTIFY_URL = "http://xx.xx.86.172:8081/asyn/notify";
|
|
|
+ private static final String REDIRECT_URL = "http://www.xx.cn/";
|
|
|
+ private static final String[] PERSON_AUTH_MODES = {"PSN_MOBILE3"};
|
|
|
+ private static final String[] WILLINGNESS_MODES = {"CODE_SMS"};
|
|
|
+ private static final String[] ORG_AUTH_MODES = {"ORG_ALIPAY_CREDIT", "ORG_LEGALREP"};
|
|
|
+ private static final int DEFAULT_EXPIRE_TIME = 86400000;
|
|
|
@Override
|
|
|
public boolean getUserIdentityInfo(String phoneNumber) throws EsignDemoException {
|
|
|
EsignHttpResponse getPsnIdentityInfo = getPsnIdentityInfo(phoneNumber);
|
|
@@ -76,12 +75,9 @@ public class ESignServiceImpl implements IESignService {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String getAuthUrl() throws EsignDemoException {
|
|
|
- LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
|
|
- SysUser sysUser = sysUserMapper.selectById(user.getId());
|
|
|
- if (null == sysUser.getPhone()) throw new JeecgBootException("请先绑定手机号");
|
|
|
+ public String getAuthUrl(String phoneNumber) throws EsignDemoException {
|
|
|
GetPsnAuthUrlDTO getPsnAuthUrlDTO = new GetPsnAuthUrlDTO();
|
|
|
- GetPsnAuthUrlDTO.PsnAuthConfig pncAuthConfig = new GetPsnAuthUrlDTO.PsnAuthConfig().setPsnAccount(sysUser.getPhone());
|
|
|
+ GetPsnAuthUrlDTO.PsnAuthConfig pncAuthConfig = new GetPsnAuthUrlDTO.PsnAuthConfig().setPsnAccount(phoneNumber);
|
|
|
getPsnAuthUrlDTO.setPsnAuthConfig(pncAuthConfig);
|
|
|
EsignHttpResponse getPsnAuthUrl = getPsnAuthUrl(getPsnAuthUrlDTO);
|
|
|
JsonObject getPsnAuthUrlObject = gson.fromJson(getPsnAuthUrl.getBody(), JsonObject.class);
|
|
@@ -92,6 +88,7 @@ public class ESignServiceImpl implements IESignService {
|
|
|
@Override
|
|
|
public boolean getOrgIdentityInfos(String orgCode) throws EsignDemoException {
|
|
|
SysDepart sysDepart = sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery().eq(SysDepart::getOrgCode, orgCode));
|
|
|
+ AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, orgCode));
|
|
|
EsignHttpResponse getOrgIdentityInfo = getOrgIdentityInfo(sysDepart.getDepartName());
|
|
|
JsonObject getOrgIdentityInfoObject = gson.fromJson(getOrgIdentityInfo.getBody(), JsonObject.class);
|
|
|
JsonElement dataElement = getOrgIdentityInfoObject.get("data");
|
|
@@ -103,8 +100,11 @@ public class ESignServiceImpl implements IESignService {
|
|
|
JsonObject dataObj = dataElement.getAsJsonObject();
|
|
|
String orgRealnameStatus = dataObj.get("realnameStatus").getAsString();
|
|
|
String orgId = dataObj.get("orgId").getAsString();
|
|
|
- sysDepart.setEsignOrgId(orgId);
|
|
|
- sysDepartMapper.updateById(sysDepart);
|
|
|
+ JsonObject jsonObject = dataObj.get("orgInfo").getAsJsonObject();
|
|
|
+ String orgIDCardNum = jsonObject.get("orgIDCardNum").getAsString();
|
|
|
+ appSite.setEsignOrgId(orgId);
|
|
|
+ appSite.setOrgIdCardNum(orgIDCardNum);
|
|
|
+ appSiteMapper.updateById(appSite);
|
|
|
return orgRealnameStatus.equals("1");
|
|
|
}
|
|
|
|
|
@@ -156,218 +156,270 @@ public class ESignServiceImpl implements IESignService {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- @Transactional
|
|
|
- public List<String> createSign(String orderCode) throws EsignDemoException {
|
|
|
- List<String> signFlowIds = new ArrayList<>();
|
|
|
- //todo
|
|
|
- AppOrder appOrder = orderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode));
|
|
|
- List<String> familyIds = List.of(appOrder.getFamilyIds().split(","));
|
|
|
- AppContractInfo appContractInfo = appAccountMapper.selectById(appOrder.getContractNo());
|
|
|
- SysDepart sysDepart = sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery().eq(SysDepart::getOrgCode, appOrder.getOrgCode()));
|
|
|
- familyIds.forEach(familyId -> {
|
|
|
- String generate32BitUUID = generate32BitUUID();
|
|
|
- FamilyMembers familyMembers = familyMembersMapper.selectById(familyId);
|
|
|
- EsignHttpResponse createByFile = null;
|
|
|
- try {
|
|
|
-// SignFlowDTO dto = new SignFlowDTO();
|
|
|
-// dto.setDocs(Arrays.asList(
|
|
|
-// new SignFlowDTO.Doc().setFileId(appContractInfo.getFileId()).setFileName(appContractInfo.getContractName())
|
|
|
-// ));
|
|
|
-// dto.setSignFlowConfig(new SignFlowDTO.SignFlowConfig()
|
|
|
-// .setSignFlowTitle(appContractInfo.getContractName())
|
|
|
-// .setSignFlowExpireTime(System.currentTimeMillis() + 86400000L)
|
|
|
-// .setAutoFinish(true)
|
|
|
-// .setNotifyUrl("http://example.com/notify")
|
|
|
-// .setRedirectConfig(new SignFlowDTO.RedirectConfig().setRedirectUrl(appContractInfo.getRedirectUrl())));
|
|
|
-// List<SignFlowDTO.Signer> signers = new ArrayList<>();
|
|
|
-// //个人用户
|
|
|
-// SignFlowDTO.Signer signer1 = new SignFlowDTO.Signer()
|
|
|
-// .setSignerType(0)
|
|
|
-// .setPsnSignerInfo(new SignFlowDTO.PsnSignerInfo()
|
|
|
-// .setPsnAccount(familyMembers.getPhone())
|
|
|
-// .setPsnInfo(new SignFlowDTO.PsnInfo().setPsnName(familyMembers.getFullName())))
|
|
|
-// .setSignFields(Collections.singletonList(
|
|
|
-// new SignFlowDTO.SignField()
|
|
|
-// .setCustomBizNum(generate32BitUUID)
|
|
|
-// .setFileId(appContractInfo.getFileId())
|
|
|
-// .setNormalSignFieldConfig(new SignFlowDTO.NormalSignFieldConfig()
|
|
|
-// .setAutoSign(false)
|
|
|
-// .setSignFieldStyle(1)
|
|
|
-// .setSignFieldPosition(Collections.singletonList(new SignFlowDTO.SignFieldPosition()
|
|
|
-// .setPositionPage("1")
|
|
|
-// .setPositionX(100)
|
|
|
-// .setPositionY(200))))));
|
|
|
-//// //企业用户
|
|
|
-//// SignFlowDTO.Signer signer2 = new SignFlowDTO.Signer()
|
|
|
-//// .setSignerType(1)
|
|
|
-//// .setSignFields(Collections.singletonList(
|
|
|
-//// new SignFlowDTO.SignField()
|
|
|
-//// .setCustomBizNum(generate32BitUUID)
|
|
|
-//// .setFileId(appContractInfo.getFileId())
|
|
|
-//// .setNormalSignFieldConfig(new SignFlowDTO.NormalSignFieldConfig()
|
|
|
-//// .setAutoSign(false)
|
|
|
-//// .setSignFieldStyle(1)
|
|
|
-//// .setSignFieldPosition(Collections.singletonList(new SignFlowDTO.SignFieldPosition()
|
|
|
-//// .setPositionPage("1")
|
|
|
-//// .setPositionX(100)
|
|
|
-//// .setPositionY(200))))));
|
|
|
-////
|
|
|
-// signers.add(signer1);
|
|
|
-//// signers.add(signer2);
|
|
|
-// dto.setSigners(signers);
|
|
|
- String dto = "{\n" +
|
|
|
- " \"docs\": [\n" +
|
|
|
- " {\n" +
|
|
|
- " \"fileId\": \""+appContractInfo.getFileId()+"\",\n" +
|
|
|
- " \"fileName\": \""+appContractInfo.getContractName()+"."+appContractInfo.getContractType()+"\"\n" +
|
|
|
- " }\n" +
|
|
|
- " ],\n" +
|
|
|
- " \"attachments\": [\n" +
|
|
|
- " {\n" +
|
|
|
- " \"fileId\": \""+appContractInfo.getFileId()+"\",\n" +
|
|
|
- " \"fileName\": \""+appContractInfo.getContractName()+"."+appContractInfo.getContractType()+"\"\n" +
|
|
|
- " }\n" +
|
|
|
- " ],\n" +
|
|
|
- " \"signFlowConfig\": {\n" +
|
|
|
- " \"signFlowTitle\": \""+appContractInfo.getContractName()+"\",\n" +
|
|
|
- " \"signFlowExpireTime\": "+(System.currentTimeMillis() + 86400000L)+",\n" +
|
|
|
- " \"autoStart\": true,\n" +
|
|
|
- " \"autoFinish\": false,\n" +
|
|
|
- " \"identityVerify\": true,\n" +
|
|
|
- " \"signConfig\": {\n" +
|
|
|
- " \"availableSignClientTypes\": \"1\",\n" +
|
|
|
- " \"showBatchDropSealButton\": true\n" +
|
|
|
- " },\n" +
|
|
|
- " \"notifyUrl\": \"http://xx.xx.86.172:8081/asyn/notify\",\n" +
|
|
|
- " \"redirectConfig\": {\n" +
|
|
|
- " \"redirectUrl\": \"http://www.xx.cn/\"\n" +
|
|
|
- " },\n" +
|
|
|
- " \"authConfig\": {\n" +
|
|
|
- " \"psnAvailableAuthModes\": [\n" +
|
|
|
- " \"PSN_FACE\"\n" +
|
|
|
- " ],\n" +
|
|
|
- " \"willingnessAuthModes\": [\n" +
|
|
|
- " \"PSN_FACE_TECENT\",\n" +
|
|
|
- " \"PSN_FACE_ALIPAY\"\n" +
|
|
|
- " ],\n" +
|
|
|
- " \"orgAvailableAuthModes\": [\n" +
|
|
|
- " \"ORG_BANK_TRANSFER\",\n" +
|
|
|
- " \"ORG_LEGALREP\"\n" +
|
|
|
- " ]\n" +
|
|
|
- " }\n" +
|
|
|
- " },\n" +
|
|
|
- " \"signFlowInitiator\": {\n" +
|
|
|
- " \"orgInitiator\": {\n" +
|
|
|
- " \"orgId\": \""+sysDepart.getEsignOrgId()+"\",\n" +
|
|
|
- " \"transactor\": {\n" +
|
|
|
- " \"psnId\": \""+familyMembers.getPsnId()+"\"\n" +
|
|
|
- " }\n" +
|
|
|
- " }\n" +
|
|
|
- " },\n" +
|
|
|
- " \"signers\": [\n" +
|
|
|
- " {\n" +
|
|
|
- " \"signConfig\": {\n" +
|
|
|
- " \"forcedReadingTime\": \"10\",\n" +
|
|
|
- " \"signOrder\": 1\n" +
|
|
|
- " },\n" +
|
|
|
- " \"noticeConfig\": {\n" +
|
|
|
- " \"noticeTypes\": \"1\"\n" +
|
|
|
- " },\n" +
|
|
|
- " \"signerType\": 0,\n" +
|
|
|
- " \"psnSignerInfo\": {\n" +
|
|
|
- " \"psnAccount\": \""+familyMembers.getPhone()+"\",\n" +
|
|
|
- " \"psnInfo\": {\n" +
|
|
|
- " \"psnName\": \""+familyMembers.getFullName()+"\",\n" +
|
|
|
- " \"psnIDCardNum\": \""+familyMembers.getIdentityCard()+"\",\n" +
|
|
|
- " \"psnIDCardType\": \"CRED_PSN_CH_IDCARD\"\n" +
|
|
|
- " }\n" +
|
|
|
- " },"+
|
|
|
- " \"signFields\": [\n" +
|
|
|
- " {\n" +
|
|
|
- " \"fileId\": \""+appContractInfo.getFileId()+"\",\n" +
|
|
|
- " \"customBizNum\": \"自定义编码0001\",\n" +
|
|
|
- " \"signFieldType\": 0,\n" +
|
|
|
- " \"normalSignFieldConfig\": {\n" +
|
|
|
- " \"autoSign\": false,\n" +
|
|
|
- " \"freeMode\": false,\n" +
|
|
|
- " \"movableSignField\": false,\n" +
|
|
|
- " \"psnSealStyles\": \"0,1\",\n" +
|
|
|
- " \"signFieldSize\": \"96\",\n" +
|
|
|
- " \"signFieldStyle\": 1,\n" +
|
|
|
- " \"signFieldPosition\": {\n" +
|
|
|
- " \"positionPage\": \"1\",\n" +
|
|
|
- " \"positionX\": 100,\n" +
|
|
|
- " \"positionY\": 200\n" +
|
|
|
- " }\n" +
|
|
|
- " },\n" +
|
|
|
- " \"signDateConfig\": {\n" +
|
|
|
- " \"dateFormat\": \"yyyy-MM-dd\",\n" +
|
|
|
- " \"showSignDate\": 1,\n" +
|
|
|
- " \"signDatePositionX\": 100,\n" +
|
|
|
- " \"signDatePositionY\": 100\n" +
|
|
|
- " }\n" +
|
|
|
- " }\n" +
|
|
|
- " ]\n" +
|
|
|
- " },\n" +
|
|
|
- " {\n" +
|
|
|
- " \"signConfig\": {\n" +
|
|
|
- " \"forcedReadingTime\": \"10\",\n" +
|
|
|
- " \"signOrder\": 2\n" +
|
|
|
- " },\n" +
|
|
|
- " \"noticeConfig\": {\n" +
|
|
|
- " \"noticeTypes\": \"1,2\"\n" +
|
|
|
- " },\n" +
|
|
|
- " \"signerType\": 1,\n" +
|
|
|
- " \"signFields\": [\n" +
|
|
|
- " {\n" +
|
|
|
- " \"customBizNum\": \"自定义编码001\",\n" +
|
|
|
- " \"fileId\": \""+appContractInfo.getFileId()+"\",\n" +
|
|
|
- " \"normalSignFieldConfig\": {\n" +
|
|
|
- " \"autoSign\": true,\n" +
|
|
|
- " \"freeMode\": false,\n" +
|
|
|
- " \"movableSignField\": false,\n" +
|
|
|
- " \"signFieldSize\": \"159\",\n" +
|
|
|
- " \"signFieldStyle\": 1,\n" +
|
|
|
- " \"signFieldPosition\": {\n" +
|
|
|
- " \"positionPage\": \"1\",\n" +
|
|
|
- " \"positionX\": 300,\n" +
|
|
|
- " \"positionY\": 200\n" +
|
|
|
- " }\n" +
|
|
|
- " },\n" +
|
|
|
- " \"signDateConfig\": {\n" +
|
|
|
- " \"dateFormat\": \"yyyy-MM-dd\",\n" +
|
|
|
- " \"showSignDate\": 1,\n" +
|
|
|
- " \"signDatePositionX\": 300,\n" +
|
|
|
- " \"signDatePositionY\": 100\n" +
|
|
|
- " }\n" +
|
|
|
- " }\n" +
|
|
|
- " ]\n" +
|
|
|
- " }\n" +
|
|
|
- " ]\n" +
|
|
|
- "}";
|
|
|
- createByFile = createByFile(dto);
|
|
|
- } catch (EsignDemoException e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
- JSONObject createByFileJsonObject = JSONObject.parseObject(createByFile.getBody());
|
|
|
- String signFlowId = createByFileJsonObject.getJSONObject("data").getString("signFlowId");
|
|
|
- System.out.println("signFlowId:" + signFlowId);
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public List<String> createSign(String orderCode){
|
|
|
+ List<String> signFlowIds = new ArrayList<>();
|
|
|
+ AppOrder appOrder = orderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery()
|
|
|
+ .eq(AppOrder::getOrderCode, orderCode));
|
|
|
+
|
|
|
+ List<String> familyIds = Arrays.asList(appOrder.getFamilyIds().split(","));
|
|
|
+ AppContractInfo contractInfo = appAccountMapper.selectById(appOrder.getContractNo());
|
|
|
+ SysDepart sysDepart = sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery()
|
|
|
+ .eq(SysDepart::getOrgCode, appOrder.getOrgCode()));
|
|
|
+
|
|
|
+ // 预加载家庭成员信息
|
|
|
+ Map<String, FamilyMembers> familyMemberMap = familyIds.stream()
|
|
|
+ .map(familyMembersMapper::selectById)
|
|
|
+ .collect(Collectors.toMap(FamilyMembers::getId, fm -> fm));
|
|
|
+
|
|
|
+ // 构建签署流程
|
|
|
+ familyIds.forEach(familyId -> {
|
|
|
+ try {
|
|
|
+ FamilyMembers familyMembers = familyMemberMap.get(familyId);
|
|
|
+ JsonObject dto = buildSignFlowDto(contractInfo, sysDepart, familyMembers);
|
|
|
+
|
|
|
+ EsignHttpResponse response = createByFile(dto.toString());
|
|
|
+ String signFlowId = extractSignFlowId(response);
|
|
|
+
|
|
|
+ log.info("生成签署流程ID: {}", signFlowId);
|
|
|
signFlowIds.add(signFlowId);
|
|
|
- appContractSignMapper.insert(new AppContractSign().setId(generate32BitUUID)
|
|
|
- .setSignFlowId(signFlowId)
|
|
|
- .setOrderId(appOrder.getId()).setFamilyId(familyId)
|
|
|
- .setOrgCode(appOrder.getOrgCode())
|
|
|
- .setCreateTime(new Date())
|
|
|
- .setUpdateTime(new Date()));
|
|
|
+ saveSignFlowRecord(signFlowId, appOrder, familyId);
|
|
|
+ } catch (EsignDemoException e) {
|
|
|
+ log.error("签署流程创建失败,订单号: {}", orderCode, e);
|
|
|
+ throw new JeecgBootException(e.getMessage());
|
|
|
+ }
|
|
|
});
|
|
|
- return signFlowIds;
|
|
|
+
|
|
|
+ return signFlowIds;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 构建签署流程请求体
|
|
|
+ */
|
|
|
+ private JsonObject buildSignFlowDto(AppContractInfo contractInfo,
|
|
|
+ SysDepart sysDepart,
|
|
|
+ FamilyMembers familyMembers) {
|
|
|
+ JsonObject dto = new JsonObject();
|
|
|
+ AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, sysDepart.getOrgCode()));
|
|
|
+ // 构建文档信息
|
|
|
+ JsonArray docs = new JsonArray();
|
|
|
+ JsonObject doc = new JsonObject();
|
|
|
+ doc.addProperty("fileId", contractInfo.getFileId());
|
|
|
+ doc.addProperty("fileName", contractInfo.getContractName() + "." + contractInfo.getContractType());
|
|
|
+ docs.add(doc);
|
|
|
+ dto.add("docs", docs);
|
|
|
+
|
|
|
+ // 构建附件信息
|
|
|
+ dto.add("attachments", docs);
|
|
|
+
|
|
|
+ // 构建签署流程配置
|
|
|
+ JsonObject signFlowConfig = new JsonObject();
|
|
|
+ signFlowConfig.addProperty("signFlowTitle", contractInfo.getContractName());
|
|
|
+ signFlowConfig.addProperty("signFlowExpireTime", System.currentTimeMillis() + DEFAULT_EXPIRE_TIME);
|
|
|
+ signFlowConfig.addProperty("autoStart", true);
|
|
|
+ signFlowConfig.addProperty("autoFinish", true);
|
|
|
+ signFlowConfig.addProperty("identityVerify", true);
|
|
|
+
|
|
|
+ // 签署配置
|
|
|
+ JsonObject signConfig = new JsonObject();
|
|
|
+ signConfig.addProperty("availableSignClientTypes", "1");
|
|
|
+ signConfig.addProperty("showBatchDropSealButton", true);
|
|
|
+ signFlowConfig.add("signConfig", signConfig);
|
|
|
+
|
|
|
+ // 通知配置
|
|
|
+ signFlowConfig.addProperty("notifyUrl", NOTIFY_URL);
|
|
|
+
|
|
|
+ // 重定向配置
|
|
|
+ JsonObject redirectConfig = new JsonObject();
|
|
|
+ redirectConfig.addProperty("redirectUrl", REDIRECT_URL);
|
|
|
+ signFlowConfig.add("redirectConfig", redirectConfig);
|
|
|
+
|
|
|
+ // 认证配置
|
|
|
+ JsonObject authConfig = new JsonObject();
|
|
|
+ addStringArray(authConfig, "psnAvailableAuthModes", PERSON_AUTH_MODES);
|
|
|
+ addStringArray(authConfig, "willingnessAuthModes", WILLINGNESS_MODES);
|
|
|
+ addStringArray(authConfig, "orgAvailableAuthModes", ORG_AUTH_MODES);
|
|
|
+ signFlowConfig.add("authConfig", authConfig);
|
|
|
+
|
|
|
+ dto.add("signFlowConfig", signFlowConfig);
|
|
|
+
|
|
|
+ // 发起人信息
|
|
|
+ JsonObject signFlowInitiator = new JsonObject();
|
|
|
+ JsonObject orgInitiator = new JsonObject();
|
|
|
+ orgInitiator.addProperty("orgId", appSite.getEsignOrgId());
|
|
|
+
|
|
|
+ JsonObject transactor = new JsonObject();
|
|
|
+ transactor.addProperty("psnId", familyMembers.getPsnId());
|
|
|
+ orgInitiator.add("transactor", transactor);
|
|
|
+
|
|
|
+ signFlowInitiator.add("orgInitiator", orgInitiator);
|
|
|
+ dto.add("signFlowInitiator", signFlowInitiator);
|
|
|
+
|
|
|
+ // 签署人信息
|
|
|
+ dto.add("signers", buildSigners(contractInfo, familyMembers));
|
|
|
+
|
|
|
+ return dto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建签署人信息
|
|
|
+ */
|
|
|
+ private JsonArray buildSigners(AppContractInfo contractInfo, FamilyMembers familyMembers) {
|
|
|
+ JsonArray signers = new JsonArray();
|
|
|
+
|
|
|
+ // 个人签署人
|
|
|
+ JsonObject signer1 = new JsonObject();
|
|
|
+ signer1.add("signConfig", buildSignConfig(1, 10));
|
|
|
+ signer1.add("noticeConfig", buildNoticeConfig(""));
|
|
|
+ signer1.addProperty("signerType", 0);
|
|
|
+
|
|
|
+ // 签署人信息
|
|
|
+ JsonObject psnSignerInfo = new JsonObject();
|
|
|
+ psnSignerInfo.addProperty("psnAccount", familyMembers.getPhone());
|
|
|
+
|
|
|
+ JsonObject psnInfo = new JsonObject();
|
|
|
+ psnInfo.addProperty("psnName", familyMembers.getFullName());
|
|
|
+ psnInfo.addProperty("psnIDCardNum", familyMembers.getIdentityCard());
|
|
|
+ psnInfo.addProperty("psnIDCardType", "CRED_PSN_CH_IDCARD");
|
|
|
+ psnSignerInfo.add("psnInfo", psnInfo);
|
|
|
+
|
|
|
+ signer1.add("psnSignerInfo", psnSignerInfo);
|
|
|
+ signer1.add("signFields", buildSignFields(contractInfo.getFileId(), 100, 200, 96, 100, 100,false));
|
|
|
+// "orgSignerInfo": {
|
|
|
+// "orgName": "XXXX企业名字",
|
|
|
+// "orgInfo": {
|
|
|
+// "orgIDCardNum": "911*******3",
|
|
|
+// "orgIDCardType": "CRED_ORG_USCC"
|
|
|
+// },
|
|
|
+// "transactorInfo": {
|
|
|
+// "psnAccount": "139****10",
|
|
|
+// "psnInfo": {
|
|
|
+// "psnName": "李四",
|
|
|
+// "psnIDCardNum": "3311********9",
|
|
|
+// "psnIDCardType": "CRED_PSN_CH_IDCARD"
|
|
|
+// }
|
|
|
+// }
|
|
|
+// },
|
|
|
+
|
|
|
+ // 企业签署人
|
|
|
+// JsonObject signer2 = new JsonObject();
|
|
|
+//
|
|
|
+// JsonObject corporate = new JsonObject();
|
|
|
+// // 签署人信息
|
|
|
+// psnSignerInfo.addProperty("psnAccount", familyMembers.getPhone());
|
|
|
+//
|
|
|
+// corporate.addProperty("psnName", familyMembers.getFullName());
|
|
|
+// corporate.addProperty("psnIDCardNum", familyMembers.getIdentityCard());
|
|
|
+// corporate.addProperty("psnIDCardType", "CRED_PSN_CH_IDCARD");
|
|
|
+// psnSignerInfo.add("psnInfo", psnInfo);
|
|
|
+//
|
|
|
+// signer1.add("orgSignerInfo", psnSignerInfo);
|
|
|
+// signer2.add("signConfig", buildSignConfig(2, 10));
|
|
|
+// signer2.add("noticeConfig", buildNoticeConfig(""));
|
|
|
+// signer2.addProperty("signerType", 1);
|
|
|
+// signer2.add("signFields", buildSignFields(contractInfo.getFileId(), 300, 200, 159, 300, 100,true));
|
|
|
+
|
|
|
+ signers.add(signer1);
|
|
|
+ return signers;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建签署配置
|
|
|
+ */
|
|
|
+ private JsonObject buildSignConfig(int signOrder, int readingTime) {
|
|
|
+ JsonObject signConfig = new JsonObject();
|
|
|
+ signConfig.addProperty("forcedReadingTime", String.valueOf(readingTime));
|
|
|
+ signConfig.addProperty("signOrder", signOrder);
|
|
|
+ return signConfig;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建通知配置
|
|
|
+ */
|
|
|
+ private JsonObject buildNoticeConfig(String noticeTypes) {
|
|
|
+ JsonObject noticeConfig = new JsonObject();
|
|
|
+ noticeConfig.addProperty("noticeTypes", noticeTypes);
|
|
|
+ return noticeConfig;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建签署区域
|
|
|
+ */
|
|
|
+ private JsonArray buildSignFields(String fileId,
|
|
|
+ int x, int y,
|
|
|
+ int size,
|
|
|
+ int dateX, int dateY,boolean autoSign) {
|
|
|
+ JsonArray signFields = new JsonArray();
|
|
|
+ JsonObject field = new JsonObject();
|
|
|
+
|
|
|
+ field.addProperty("fileId", fileId);
|
|
|
+ field.addProperty("customBizNum", "自定义编码0001");
|
|
|
+ field.addProperty("signFieldType", 0);
|
|
|
+
|
|
|
+ // 签署配置
|
|
|
+ JsonObject normalConfig = new JsonObject();
|
|
|
+ normalConfig.addProperty("autoSign", autoSign);
|
|
|
+ normalConfig.addProperty("freeMode", false);
|
|
|
+ normalConfig.addProperty("movableSignField", false);
|
|
|
+ normalConfig.addProperty("psnSealStyles", "0,1");
|
|
|
+ normalConfig.addProperty("signFieldSize", String.valueOf(size));
|
|
|
+ normalConfig.addProperty("signFieldStyle", 1);
|
|
|
+
|
|
|
+ // 位置配置
|
|
|
+ JsonObject position = new JsonObject();
|
|
|
+ position.addProperty("positionPage", "1");
|
|
|
+ position.addProperty("positionX", x);
|
|
|
+ position.addProperty("positionY", y);
|
|
|
+ normalConfig.add("signFieldPosition", position);
|
|
|
+
|
|
|
+ // 日期配置
|
|
|
+ JsonObject dateConfig = new JsonObject();
|
|
|
+ dateConfig.addProperty("dateFormat", "yyyy-MM-dd");
|
|
|
+ dateConfig.addProperty("showSignDate", 1);
|
|
|
+ dateConfig.addProperty("signDatePositionX", dateX);
|
|
|
+ dateConfig.addProperty("signDatePositionY", dateY);
|
|
|
+
|
|
|
+ field.add("normalSignFieldConfig", normalConfig);
|
|
|
+ field.add("signDateConfig", dateConfig);
|
|
|
+
|
|
|
+ signFields.add(field);
|
|
|
+ return signFields;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提取签署流程ID
|
|
|
+ */
|
|
|
+ private String extractSignFlowId(EsignHttpResponse response) {
|
|
|
+ JSONObject result = JSONObject.parseObject(response.getBody());
|
|
|
+ return result.getJSONObject("data").getString("signFlowId");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存签署流程记录
|
|
|
+ */
|
|
|
+ private void saveSignFlowRecord(String signFlowId, AppOrder appOrder, String familyId) {
|
|
|
+ String id = UUID.randomUUID().toString().replace("-", "");
|
|
|
+ AppContractSign record = new AppContractSign()
|
|
|
+ .setId(id)
|
|
|
+ .setSignFlowId(signFlowId)
|
|
|
+ .setOrderId(appOrder.getId())
|
|
|
+ .setFamilyId(familyId)
|
|
|
+ .setOrgCode(appOrder.getOrgCode())
|
|
|
+ .setCreateTime(new Date())
|
|
|
+ .setUpdateTime(new Date());
|
|
|
+ appContractSignMapper.insert(record);
|
|
|
}
|
|
|
- public static String generate32BitUUID() {
|
|
|
- // 生成标准 UUID(128 位)
|
|
|
- UUID uuid = UUID.randomUUID();
|
|
|
- // 去除连字符,得到 32 位字符串
|
|
|
- return uuid.toString().replace("-", "");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加字符串数组到JSON对象
|
|
|
+ */
|
|
|
+ private void addStringArray(JsonObject parent, String key, String[] values) {
|
|
|
+ JsonArray array = new JsonArray();
|
|
|
+ for (String value : values) {
|
|
|
+ array.add(value);
|
|
|
+ }
|
|
|
+ parent.add(key, array);
|
|
|
}
|
|
|
+
|
|
|
@Override
|
|
|
public String getSignUrl(String signFlowId) throws EsignDemoException {
|
|
|
AppContractSign appContractSign = appContractSignMapper.selectOne(Wrappers.<AppContractSign>lambdaQuery().eq(AppContractSign::getSignFlowId, signFlowId));
|
|
@@ -437,43 +489,79 @@ public class ESignServiceImpl implements IESignService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 获取文件扩展名
|
|
|
- */
|
|
|
- private String getFileExtension(String filename) {
|
|
|
- if (filename == null || !filename.contains(".")) {
|
|
|
- return "";
|
|
|
+ @Override
|
|
|
+ public List<SealInfoDTO> orgOwnSeal(String orgId) {
|
|
|
+ try {
|
|
|
+ // 调用API获取响应
|
|
|
+ EsignHttpResponse response = orgOwnSealList(orgId);
|
|
|
+
|
|
|
+ // 解析JSON响应
|
|
|
+ JsonObject result = gson.fromJson(response.getBody(), JsonObject.class);
|
|
|
+
|
|
|
+ // 验证数据结构
|
|
|
+ if (!result.has("data")) {
|
|
|
+ throw new JeecgBootException("响应数据中缺少'data'字段");
|
|
|
+ }
|
|
|
+
|
|
|
+ JsonObject data = result.getAsJsonObject("data");
|
|
|
+
|
|
|
+ if (!data.has("seals")) {
|
|
|
+ throw new JeecgBootException("响应数据中缺少'seals'字段");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换数据
|
|
|
+ return gson.fromJson(data.getAsJsonArray("seals"),
|
|
|
+ new TypeToken<List<SealInfoDTO>>(){}.getType());
|
|
|
+
|
|
|
+ } catch (JsonSyntaxException e) {
|
|
|
+ throw new JeecgBootException("JSON解析失败: " + e.getMessage(), e);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new JeecgBootException("获取印章列表失败: " + e.getMessage(), e);
|
|
|
}
|
|
|
- return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 下载远程文件
|
|
|
- */
|
|
|
- private File downloadRemoteFile(String fileUrl) throws IOException {
|
|
|
- URL url = new URL(fileUrl);
|
|
|
- File tempFile = File.createTempFile("esign-", ".tmp");
|
|
|
- tempFile.deleteOnExit();
|
|
|
-
|
|
|
- try (InputStream in = url.openStream()) {
|
|
|
- Files.copy(in, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
|
+ @Override
|
|
|
+ public Boolean orgSealsExternal(String orgCode, String sealId) throws EsignDemoException {
|
|
|
+ AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, orgCode));
|
|
|
+ EsignHttpResponse administrators = administrators(appSite.getEsignOrgId());
|
|
|
+ JsonObject administratorsObject = gson.fromJson(administrators.getBody(), JsonObject.class);
|
|
|
+ JsonObject data = administratorsObject.getAsJsonObject("data");
|
|
|
+ String psnId = null;
|
|
|
+ if (data != null) {
|
|
|
+ JsonArray admins = data.getAsJsonArray("administrators");
|
|
|
+ if (admins != null && !admins.isEmpty()) {
|
|
|
+ JsonObject firstAdmin = admins.get(0).getAsJsonObject();
|
|
|
+ if (firstAdmin.has("psnId")) {
|
|
|
+ psnId = firstAdmin.get("psnId").getAsString();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ ExternalAuthRequestDTO requestDTO = new ExternalAuthRequestDTO();
|
|
|
+ requestDTO.setOrgId(appSite.getEsignOrgId());
|
|
|
+ requestDTO.setTransactorPsnId(psnId);
|
|
|
+ requestDTO.setLongTermEffective(true);
|
|
|
+ requestDTO.setSealIds(Collections.singletonList(sealId));
|
|
|
+
|
|
|
+ ExternalAuthRequestDTO.AuthorizedOrgInfoDTO orgInfo = new ExternalAuthRequestDTO.AuthorizedOrgInfoDTO();
|
|
|
+ orgInfo.setOrgName("中数未来(海南)系统集成有限公司");
|
|
|
+ orgInfo.setOrgIdCardNum("91460105MAA9A6L75X");
|
|
|
+ requestDTO.setAuthorizedOrgInfo(orgInfo);
|
|
|
+
|
|
|
+ EsignHttpResponse orgSealsExternalAuth = orgSealsExternalAuth(requestDTO);
|
|
|
+ JsonObject orgSealsExternalAuthObject = gson.fromJson(orgSealsExternalAuth.getBody(), JsonObject.class);
|
|
|
+ System.out.println("请求返回:"+orgSealsExternalAuthObject);
|
|
|
|
|
|
- return tempFile;
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取MIME类型映射
|
|
|
+ * 获取文件扩展名
|
|
|
*/
|
|
|
- private String getMimeType(String ext) {
|
|
|
- Map<String, String> mimeMap = new HashMap<>();
|
|
|
- mimeMap.put("pdf", "application/pdf");
|
|
|
- mimeMap.put("doc", "application/msword");
|
|
|
- mimeMap.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
|
|
- mimeMap.put("xls", "application/vnd.ms-excel");
|
|
|
- mimeMap.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
-
|
|
|
- return mimeMap.getOrDefault(ext, "application/octet-stream");
|
|
|
+ private String getFileExtension(String filename) {
|
|
|
+ if (filename == null || !filename.contains(".")) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
|
|
|
}
|
|
|
}
|
|
|
|