Browse Source

feat(app): 优化合同模板功能

- 修改模板创建逻辑,增加签名角色
- 新增合同预览功能
- 优化文件下载方法
- 修复模板编辑问题
SheepHy 1 day ago
parent
commit
e00755a94b

+ 14 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/ESignController.java

@@ -19,7 +19,7 @@ import java.util.Map;
 @Slf4j
 @Tag(name = "web管理E签宝相关接口")
 @RestController
-@RequestMapping("/app/esign/web")
+@RequestMapping("/api/esign")
 public class ESignController {
     @Resource
     private IESignService iESignService;
@@ -142,4 +142,17 @@ public class ESignController {
                                             @RequestParam("sealId")@Schema(description="签章ID")String sealId) throws EsignDemoException{
         return Result.OK(iESignService.orgSealsExternal(orgCode, sealId));
     }
+
+    /**
+     * @Author SheepHy
+     * @Description 获取合同预览页
+     * @Date 13:36 2025/8/1
+     * @Param
+     * @return
+     **/
+    @GetMapping("/templatePreviewUrl")
+    @Operation(summary = "获取合同预览页-PC")
+    public Result<String> templatePreviewUrl(@RequestParam("docTemplateId")@Schema(description="合同模板ID")String docTemplateId) throws EsignDemoException{
+        return Result.OK(iESignService.templatePreviewUrl(docTemplateId));
+    }
 }

+ 5 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/DocTemplateDTO.java

@@ -5,6 +5,8 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import java.util.List;
+
 @Data
 @Accessors(chain = true)
 @EqualsAndHashCode(callSuper = false)
@@ -21,4 +23,7 @@ public class DocTemplateDTO {
 
     @Schema(description = "重定向URL")
     private String redirectUrl;
+
+    @Schema(description = "签署方角色标识")
+    private List<String> signerRoles;
 }

+ 7 - 3
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/comm/EsignFileBean.java

@@ -7,6 +7,7 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
+import java.net.URI;
 import java.net.URL;
 
 /**
@@ -50,20 +51,23 @@ public class EsignFileBean {
 
     private File downloadFromURL(String fileUrl) throws EsignDemoException {
         try {
-            URL url = new URL(fileUrl);
+            // 使用 URI 构造器自动编码路径
+            URI uri = new URI(fileUrl);
+            URL url = uri.toURL();
+
             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
             connection.setRequestMethod("GET");
+            connection.setRequestProperty("User-Agent", "Mozilla/5.0"); // 模拟浏览器请求
             connection.connect();
 
             if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                 throw new EsignDemoException("网络文件下载失败,状态码:" + connection.getResponseCode());
             }
 
-            // 提取文件名(从URL或Content-Disposition)
             String fileName = extractFileNameFromURL(url, connection);
             File targetFile = new File(getDownloadDirectory(), fileName);
 
-            // 确保文件名唯一(可选)
+            // 确保文件名唯一
             int count = 1;
             String baseName = fileName.substring(0, fileName.lastIndexOf('.'));
             String ext = fileName.substring(fileName.lastIndexOf('.'));

+ 43 - 15
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/fileAndTemplate/TemplateDemo.java

@@ -9,6 +9,7 @@ import org.jeecg.modules.app.esign.constant.EsignDemoConfig;
 import org.jeecg.modules.app.esign.enums.EsignRequestType;
 import org.jeecg.modules.app.esign.exception.EsignDemoException;
 
+import java.util.HashMap;
 import java.util.Map;
 /**
  * description 模板服务
@@ -39,23 +40,27 @@ public class TemplateDemo extends Exception {
 //		System.err.println("编辑合同模板的页面链接:"+docTemplateEditUrl);
 
 		/* 查询合同模板中控件详情*/
-		EsignHttpResponse getComponentsInfo = getComponentsInfo();
+		EsignHttpResponse getComponentsInfo = getComponentsInfo("12f41e8f364946369b8d93bd8710df67");
 		JsonObject getComponentsInfoObject = gson.fromJson(getComponentsInfo.getBody(), JsonObject.class);
 		System.err.println("查询模板详情返回:"+getComponentsInfoObject);
 
 
-		/* 填写模板生成文件*/
-		EsignHttpResponse createByDocTemplate = createByDocTemplate();
-		JsonObject createByDocTemplateObject = gson.fromJson(createByDocTemplate.getBody(), JsonObject.class);
-		String fileId = createByDocTemplateObject.getAsJsonObject("data").get("fileId").getAsString();
-		String fileDownloadUrl = createByDocTemplateObject.getAsJsonObject("data").get("fileDownloadUrl").getAsString();
-		System.err.println("填充后文件id:"+fileId);
-		System.err.println("文件下载链接:"+fileDownloadUrl);
-
-		//删除合同模板
-		EsignHttpResponse deleteDocTemplate = deleteDocTemplate();
-		JsonObject deleteDocTemplateObject = gson.fromJson(deleteDocTemplate.getBody(), JsonObject.class);
-		System.err.println("删除模板文件返回:"+deleteDocTemplateObject);
+//		EsignHttpResponse getTemplatePreview = getTemplatePreviewUrl("b247e5128104408ea6684a504a0d8910");
+//		JsonObject getTemplatePreview1 = gson.fromJson(getTemplatePreview.getBody(), JsonObject.class);
+//		System.err.println("查询模板详情返回:"+getTemplatePreview1);
+
+//		/* 填写模板生成文件*/
+//		EsignHttpResponse createByDocTemplate = createByDocTemplate();
+//		JsonObject createByDocTemplateObject = gson.fromJson(createByDocTemplate.getBody(), JsonObject.class);
+//		String fileId = createByDocTemplateObject.getAsJsonObject("data").get("fileId").getAsString();
+//		String fileDownloadUrl = createByDocTemplateObject.getAsJsonObject("data").get("fileDownloadUrl").getAsString();
+//		System.err.println("填充后文件id:"+fileId);
+//		System.err.println("文件下载链接:"+fileDownloadUrl);
+//
+//		//删除合同模板
+//		EsignHttpResponse deleteDocTemplate = deleteDocTemplate();
+//		JsonObject deleteDocTemplateObject = gson.fromJson(deleteDocTemplate.getBody(), JsonObject.class);
+//		System.err.println("删除模板文件返回:"+deleteDocTemplateObject);
 	}
 	/**
 	 * 获取制作合同模板页面
@@ -75,6 +80,30 @@ public class TemplateDemo extends Exception {
 		//发起接口请求
 		return EsignHttpHelper.doCommHttp(eSignHost, apiaddr,requestType , jsonParm, header,true);
 	}
+
+	/**
+	 * @Author SheepHy
+	 * @Description 获取合同预览页
+	 * @Date 13:36 2025/8/1
+	 * @Param
+	 * @return
+	 **/
+	public static EsignHttpResponse getTemplatePreviewUrl(String docTemplateId) throws EsignDemoException {
+		String apiaddr="/v3/doc-templates/doc-template-preview-url";
+		//请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
+		Gson gson = new Gson();
+		Map<String, String> docTemplateIdMap = new HashMap<>();
+		docTemplateIdMap.put("docTemplateId", docTemplateId);
+		String jsonParm = gson.toJson(docTemplateIdMap);
+
+		//请求方法
+		EsignRequestType requestType= EsignRequestType.POST;
+		//生成签名鉴权方式的的header
+		Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId,eSignAppSecret,jsonParm,requestType.name(),apiaddr,true);
+		//发起接口请求
+		return EsignHttpHelper.doCommHttp(eSignHost, apiaddr,requestType , jsonParm, header,true);
+	}
+
 	/**
 	 * 获取编辑合同模板页面
 	 * @return
@@ -95,8 +124,7 @@ public class TemplateDemo extends Exception {
 	/**
 	 * 查询合同模板中控件详情
 	 */
-	public static EsignHttpResponse getComponentsInfo() throws EsignDemoException {
-		String docTemplateId="a6f7e3b4xxxxxxxxfdedc6fc89";
+	public static EsignHttpResponse getComponentsInfo(String docTemplateId) throws EsignDemoException {
 		String apiaddr="/v3/doc-templates/"+docTemplateId;
 
 		//请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null

+ 2 - 3
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/esign/seal/SealDemo.java

@@ -56,7 +56,7 @@ public class SealDemo {
 //        JsonObject orgOwnSealListObject = gson.fromJson(orgOwnSealList.getBody(), JsonObject.class);
 //        System.out.println("请求返回:"+orgOwnSealListObject);
         //查询被外部企业授权印章
-        EsignHttpResponse orgAuthorizedSealList = orgAuthorizedSealList();
+        EsignHttpResponse orgAuthorizedSealList = orgAuthorizedSealList("585f3eabc65b42b1ad5ae56f4e2bdde6");
         JsonObject orgAuthorizedSealListObject = gson.fromJson(orgAuthorizedSealList.getBody(), JsonObject.class);
         System.out.println("请求返回:"+orgAuthorizedSealListObject);
         //跨企业印章授权
@@ -184,8 +184,7 @@ public class SealDemo {
      * 查询被外部企业授权印章
      */
 
-    public static EsignHttpResponse orgAuthorizedSealList() throws EsignDemoException {
-        String orgId="ebeefbce5843482b94d3bfe24dd5959c";
+    public static EsignHttpResponse orgAuthorizedSealList(String orgId) throws EsignDemoException {
         int pageNum=1;
         int pageSize=10;
         String apiaddr="/v3/seals/org-authorized-seal-list?orgId="+orgId+"&pageNum="+pageNum+"&pageSize="+pageSize;

+ 9 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IESignService.java

@@ -128,4 +128,13 @@ public interface IESignService {
      * @return 
      **/
     Boolean orgSealsExternal(String orgCode, String sealId) throws EsignDemoException;
+
+    /**
+     * @Author SheepHy
+     * @Description 获取合同预览页
+     * @Date 13:36 2025/8/1
+     * @Param
+     * @return
+     **/
+    String templatePreviewUrl(String docTemplateId) throws EsignDemoException;
 }

+ 1 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/DetailServiceImpl.java

@@ -110,7 +110,7 @@ public class DetailServiceImpl implements IDetailService {
                                 .eq(AppSitePriceRules::getSitePlaceId, appSitePlace.getId())
                                 .last("limit 1").orderByDesc(AppSitePriceRules::getSellingPrice)).getSellingPrice())
                         .setCategory(getCategoryName(appSitePlace.getCategoryId()))
-                        .setCover(appSitePlace.getCover())
+                        .setCover(appSitePlace.getCover().split(",")[0])
                         .setReminder(appSitePlace.getReminder())
                         .setRefundType(appSitePlace.getRefundType());
                 placeInfoMsgVOS.add(placeInfoMsgVO);

+ 77 - 47
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/ESignServiceImpl.java

@@ -32,11 +32,9 @@ 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.fileAndTemplate.TemplateDemo.*;
 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.seal.SealDemo.*;
 import static org.jeecg.modules.app.esign.sign.SignDemo.createByFile;
 
 @Service
@@ -56,8 +54,8 @@ public class ESignServiceImpl implements IESignService {
     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 NOTIFY_URL = "";
+    private static final String REDIRECT_URL = "";
     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"};
@@ -119,8 +117,7 @@ public class ESignServiceImpl implements IESignService {
     @Override
     public boolean uploadContractTemplate(AppContractInfoDTO appContractInfoDTO) throws EsignDemoException {
         LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-//        String remoteUrl = "http://127.0.0.1:8080/jeecg-boot/sys/common/static/" + appContractInfoDTO.getFilePath();
-        String remoteUrl = "E:/合同模板/test-template1.pdf";
+        String remoteUrl = "http://127.0.0.1:8080/jeecg-boot/sys/common/static/" + appContractInfoDTO.getFilePath();
         String fileType = getFileExtension(appContractInfoDTO.getFilePath());
         if (fileType.isEmpty()) {
             throw new JeecgBootException("未指定文件类型");
@@ -140,6 +137,11 @@ public class ESignServiceImpl implements IESignService {
         if (errCode == 0) {
             appAccountMapper.delete(Wrappers.<AppContractInfo>lambdaQuery()
                     .eq(AppContractInfo::getOrgCode, user.getOrgCode()));
+            AppContractInfo appContractInfo = appAccountMapper.selectOne(Wrappers.<AppContractInfo>lambdaQuery()
+                    .eq(AppContractInfo::getFileId, fileId));
+            if(null != appContractInfo){
+                appAccountMapper.deleteById(appContractInfo);
+            }
             appAccountMapper.insert(new AppContractInfo()
                     .setOrgCode(user.getOrgCode())
                     .setFileId(fileId)
@@ -197,7 +199,7 @@ public class ESignServiceImpl implements IESignService {
      */
     private JsonObject buildSignFlowDto(AppContractInfo contractInfo,
                                         SysDepart sysDepart,
-                                        FamilyMembers familyMembers) {
+                                        FamilyMembers familyMembers) throws EsignDemoException {
         JsonObject dto = new JsonObject();
         AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, sysDepart.getOrgCode()));
         // 构建文档信息
@@ -255,7 +257,7 @@ public class ESignServiceImpl implements IESignService {
         dto.add("signFlowInitiator", signFlowInitiator);
 
         // 签署人信息
-        dto.add("signers", buildSigners(contractInfo, familyMembers));
+        dto.add("signers", buildSigners(contractInfo, familyMembers,appSite.getEsignOrgId()));
 
         return dto;
     }
@@ -263,9 +265,11 @@ public class ESignServiceImpl implements IESignService {
     /**
      * 构建签署人信息
      */
-    private JsonArray buildSigners(AppContractInfo contractInfo, FamilyMembers familyMembers) {
+    private JsonArray buildSigners(AppContractInfo contractInfo, FamilyMembers familyMembers,String orgId) throws EsignDemoException {
         JsonArray signers = new JsonArray();
-
+        EsignHttpResponse getComponentsInfo = getComponentsInfo("12f41e8f364946369b8d93bd8710df67");
+        JsonObject getComponentsInfoObject = gson.fromJson(getComponentsInfo.getBody(), JsonObject.class);
+        System.err.println("查询模板详情返回:"+getComponentsInfoObject);
         // 个人签署人
         JsonObject signer1 = new JsonObject();
         signer1.add("signConfig", buildSignConfig(1, 10));
@@ -283,42 +287,16 @@ public class ESignServiceImpl implements IESignService {
         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"
-//                }
-//            }
-//        },
-
+        signer1.add("signFields", buildSignFields(contractInfo.getFileId(), 100, 200, 96, 100, 100,false,""));
         // 企业签署人
-//        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));
+        JsonObject signer2 = new JsonObject();
+        signer2.addProperty("signerType", 1);
+        JsonObject orgSignerInfo = new JsonObject();
+        orgSignerInfo.addProperty("orgId", orgId);
+        signer2.add("signFields", buildSignFields(contractInfo.getFileId(), 300, 200, 159, 300, 100,true,orgAuthorizedSeal(orgId)));
 
         signers.add(signer1);
+        signers.add(signer2);
         return signers;
     }
 
@@ -347,7 +325,7 @@ public class ESignServiceImpl implements IESignService {
     private JsonArray buildSignFields(String fileId,
                                       int x, int y,
                                       int size,
-                                      int dateX, int dateY,boolean autoSign) {
+                                      int dateX, int dateY,boolean autoSign,String signature) {
         JsonArray signFields = new JsonArray();
         JsonObject field = new JsonObject();
 
@@ -363,6 +341,7 @@ public class ESignServiceImpl implements IESignService {
         normalConfig.addProperty("psnSealStyles", "0,1");
         normalConfig.addProperty("signFieldSize", String.valueOf(size));
         normalConfig.addProperty("signFieldStyle", 1);
+        normalConfig.addProperty("assignedSealId", signature);
 
         // 位置配置
         JsonObject position = new JsonObject();
@@ -432,11 +411,15 @@ public class ESignServiceImpl implements IESignService {
     @Override
     public String createTemplate(String fileId) throws EsignDemoException {
         AppContractInfo appContractInfo = appAccountMapper.selectOne(Wrappers.<AppContractInfo>lambdaQuery().eq(AppContractInfo::getFileId, fileId));
+        List<String> signerRoles = new ArrayList<>();
+        signerRoles.add("商户");
+        signerRoles.add("用户");
         DocTemplateDTO docTemplateDTO = new DocTemplateDTO()
                 .setDocTemplateName(appContractInfo.getContractName())
                 .setDocTemplateType(0)
                 .setFileId(fileId)
-                .setRedirectUrl(appContractInfo.getRedirectUrl());
+                .setRedirectUrl(appContractInfo.getRedirectUrl())
+                .setSignerRoles(signerRoles);
         /* 获取制作合同模板页面*/
         EsignHttpResponse getTemplateCreateUrl = getTemplateCreateUrl(docTemplateDTO);
         Gson gson = new Gson();
@@ -554,6 +537,53 @@ public class ESignServiceImpl implements IESignService {
         return null;
     }
 
+    @Override
+    public String templatePreviewUrl(String docTemplateId) throws EsignDemoException {
+        EsignHttpResponse getTemplatePreview = getTemplatePreviewUrl(docTemplateId);
+        JsonObject getTemplatePreview1 = gson.fromJson(getTemplatePreview.getBody(), JsonObject.class);
+
+        // 检查 data 对象是否存在
+        if (!getTemplatePreview1.has("data") || !getTemplatePreview1.get("data").isJsonObject()) {
+            throw new EsignDemoException("响应中缺少 data 字段");
+        }
+
+        JsonObject data = getTemplatePreview1.getAsJsonObject("data");
+
+        // 提取 docTemplatePreviewUrl
+        if (!data.has("docTemplatePreviewUrl") || !data.get("docTemplatePreviewUrl").isJsonPrimitive()) {
+            throw new EsignDemoException("缺少 docTemplatePreviewUrl 字段");
+        }
+
+        String previewUrl = data.get("docTemplatePreviewUrl").getAsString();
+        System.err.println("查询模板详情返回:" + previewUrl);
+        return previewUrl;
+    }
+
+    public String orgAuthorizedSeal(String orgId) throws EsignDemoException {
+        // 使用传入的 orgId
+        EsignHttpResponse orgAuthorizedSealList = orgAuthorizedSealList("585f3eabc65b42b1ad5ae56f4e2bdde6");
+        JsonObject orgAuthorizedSealListObject = gson.fromJson(orgAuthorizedSealList.getBody(), JsonObject.class);
+
+        // 检查 data.seals 是否存在
+        if (orgAuthorizedSealListObject.has("data") &&
+                orgAuthorizedSealListObject.getAsJsonObject("data").has("seals")) {
+
+            JsonArray seals = orgAuthorizedSealListObject.getAsJsonObject("data").getAsJsonArray("seals");
+
+            for (JsonElement sealElement : seals) {
+                JsonObject seal = sealElement.getAsJsonObject();
+                // 条件判断
+                if (orgId.equals(seal.get("authorizerOrgId").getAsString()) &&
+                        "PUBLIC".equals(seal.get("sealBizType").getAsString())) {
+
+                    return seal.get("sealId").getAsString(); // 返回匹配的 sealAuthBizId
+                }
+            }
+        }
+
+        return null; // 无匹配项返回 null
+    }
+
     /**
      * 获取文件扩展名
      */