瀏覽代碼

feat(app): 优化印章查询接口并添加授权状态字段

-将 orgOwnSeal 方法的参数从 orgId 改为 orgCode
- 新增 isStatus 字段表示印章是否已授权
-优化印章数据处理逻辑,过滤出 PUBLIC 类型的印章
-为每个印章查询授权信息,并设置 isStatus 字段
- 新增 SignPositionGroup 类用于表示签署位置信息
SheepHy 2 天之前
父節點
當前提交
4c8e4b09d9

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

@@ -125,8 +125,8 @@ public class ESignController {
      **/
     @GetMapping("/orgOwnSeal")
     @Operation(summary = "查询企业内部印章-PC")
-    public Result<List<SealInfoDTO>> orgOwnSeal(@RequestParam(name = "orgId") @Schema(description="E签宝组织ID")String orgId){
-        return Result.OK(iESignService.orgOwnSeal(orgId));
+    public Result<List<SealInfoDTO>> orgOwnSeal(@RequestParam(name = "orgCode") @Schema(description="E签宝组织ID")String orgCode){
+        return Result.OK(iESignService.orgOwnSeal(orgCode));
     }
 
     /**

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

@@ -22,4 +22,7 @@ public class SealInfoDTO {
     private String sealBizTypeDescription;
     @Schema(description ="签章图片下载地址")
     private String sealImageDownloadUrl;
+    @Schema(description ="是否授权")
+    private Boolean isStatus;
+    private String orgCode;
 }

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

@@ -0,0 +1,28 @@
+package org.jeecg.modules.app.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+public class SignPositionGroup {
+    private List<ComponentPosition> merchant;  // 商户位置
+    private List<ComponentPosition> customer;  // 用户位置
+
+    // Getters and Setters
+    @Data
+    @Accessors(chain = true)
+    public static class ComponentPosition {
+        private int x;
+        private int y;
+
+        // Constructor
+        public ComponentPosition(int x, int y) {
+            this.x = x;
+            this.y = y;
+        }
+    }
+}

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

@@ -180,6 +180,23 @@ public class SealDemo {
         //发起接口请求
         return EsignHttpHelper.doCommHttp(eSignHost, apiaddr,requestType , jsonParm, header,true);
     }
+
+    /**
+     * 查询对外部企业印章授权详情
+     */
+    public static EsignHttpResponse orgSealsExternalAuth(String orgId,String sealId) throws EsignDemoException {
+        int pageNum=1;
+        int pageSize=10;
+        String apiaddr="/v3/seals/org-seals/external-auth?orgId="+orgId+"&pageNum="+pageNum+"&pageSize="+pageSize+"&sealId="+sealId;
+        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
+        String jsonParm=null;
+        //请求方法
+        EsignRequestType requestType= EsignRequestType.GET;
+        //生成签名鉴权方式的的header
+        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId,eSignAppSecret,jsonParm,requestType.name(),apiaddr,true);
+        //发起接口请求
+        return EsignHttpHelper.doCommHttp(eSignHost, apiaddr,requestType , jsonParm, header,true);
+    }
     /**
      * 查询被外部企业授权印章
      */

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

@@ -118,7 +118,7 @@ public interface IESignService {
      * @Param
      * @return
      **/
-    List<SealInfoDTO> orgOwnSeal(String orgId);
+    List<SealInfoDTO> orgOwnSeal(String orgCode);
     
     /** 
      * @Author SheepHy

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

@@ -8,10 +8,7 @@ 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.dto.*;
 import org.jeecg.modules.app.esign.comm.EsignHttpResponse;
 import org.jeecg.modules.app.esign.exception.EsignDemoException;
 import org.jeecg.modules.app.esign.fileAndTemplate.FileDemo;
@@ -160,39 +157,39 @@ public class ESignServiceImpl implements IESignService {
     @Override
     @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);
-            saveSignFlowRecord(signFlowId, appOrder, familyId);
-        } catch (EsignDemoException e) {
-            log.error("签署流程创建失败,订单号: {}", orderCode, e);
-            throw new JeecgBootException(e.getMessage());
-        }
+        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);
+                saveSignFlowRecord(signFlowId, appOrder, familyId);
+            } catch (EsignDemoException e) {
+                log.error("签署流程创建失败,订单号: {}", orderCode, e);
+                throw new JeecgBootException(e.getMessage());
+            }
         });
 
-    return signFlowIds;
+        return signFlowIds;
     }
     /**
      * 构建签署流程请求体
@@ -262,76 +259,55 @@ public class ESignServiceImpl implements IESignService {
         return dto;
     }
 
-    /**
-     * 构建签署人信息
-     */
-    private JsonArray buildSigners(AppContractInfo contractInfo, FamilyMembers familyMembers,String orgId) throws EsignDemoException {
-        JsonArray signers = new JsonArray();
-
-        // 获取模板组件信息
-        EsignHttpResponse getComponentsInfo = getComponentsInfo(contractInfo.getDocTemplateId());
-        JsonObject getComponentsInfoObject = gson.fromJson(getComponentsInfo.getBody(), JsonObject.class);
+    private SignPositionGroup groupComponentPositions(JsonObject getComponentsInfoObject) {
+        SignPositionGroup group = new SignPositionGroup();
+        List<SignPositionGroup.ComponentPosition> merchant = new ArrayList<>();
+        List<SignPositionGroup.ComponentPosition> customer = new ArrayList<>();
 
-        if (!getComponentsInfoObject.has("data") || !getComponentsInfoObject.getAsJsonObject("data").has("components")) {
-            throw new EsignDemoException("模板组件信息缺失");
-        }
-
-        JsonArray components = getComponentsInfoObject.getAsJsonObject("data").getAsJsonArray("components");
+        JsonArray components = getComponentsInfoObject
+                .getAsJsonObject("data")
+                .getAsJsonArray("components");
 
-        // 构建签署人结构
-        JsonObject signer1 = new JsonObject();
-        JsonObject signer2 = new JsonObject();
-        JsonArray personalSignFields = new JsonArray();
-        JsonArray enterpriseSignFields = new JsonArray();
-
-        // 设置签署人基础信息
-        setupSignerBaseInfo(signer1, familyMembers, 0); // 个人签署人
-        if (orgId != null) {
-            setupEnterpriseSigner(signer2, orgId); // 企业签署人
-        }
-
-        // 遍历组件并分配签署区域
         for (JsonElement element : components) {
             JsonObject component = element.getAsJsonObject();
-            JsonObject specialAttribute = component.getAsJsonObject("componentSpecialAttribute");
+            String role = component
+                    .getAsJsonObject("componentSpecialAttribute")
+                    .get("signerRole").getAsString();
 
-            if (specialAttribute != null && specialAttribute.has("signerRole")) {
-                String signerRole = specialAttribute.get("signerRole").getAsString();
-                JsonObject position = component.getAsJsonObject("componentPosition");
-                JsonObject size = component.getAsJsonObject("componentSize");
+            JsonObject position = component
+                    .getAsJsonObject("componentPosition");
 
-                int x = position.get("componentPositionX").getAsInt();
-                int y = position.get("componentPositionY").getAsInt();
-                int width = size.get("componentWidth").getAsInt();
-                int height = size.get("componentHeight").getAsInt();
+            int x = position.get("componentPositionX").getAsInt();
+            int y = position.get("componentPositionY").getAsInt();
 
-                JsonObject signField = buildSignFieldFromComponent(contractInfo.getFileId(), x, y, width, height, "商户".equals(signerRole));
+            SignPositionGroup.ComponentPosition cp = new SignPositionGroup.ComponentPosition(x, y);
 
-                if ("用户".equals(signerRole)) {
-                    personalSignFields.add(signField);
-                } else if ("商户".equals(signerRole)) {
-                    enterpriseSignFields.add(signField);
-                }
+            if ("商户".equals(role)) {
+                merchant.add(cp);
+            } else if ("用户".equals(role)) {
+                customer.add(cp);
             }
         }
-
-        // 添加签署区域
-        if (!personalSignFields.isEmpty()) {
-            signer1.add("signFields", personalSignFields);
-            signers.add(signer1);
-        }
-
-        if (!enterpriseSignFields.isEmpty()) {
-            signer2.add("signFields", enterpriseSignFields);
-            signers.add(signer2);
-        }
-
-        return signers;
+        group.setMerchant(merchant);
+        group.setCustomer(customer);
+        return group;
     }
 
-
-    private void setupSignerBaseInfo(JsonObject signer, FamilyMembers familyMembers, int signerType) {
-        signer.addProperty("signerType", signerType);
+    /**
+     * 构建签署人信息
+     */
+    private JsonArray buildSigners(AppContractInfo contractInfo, FamilyMembers familyMembers,String orgId) throws EsignDemoException {
+        JsonArray signers = new JsonArray();
+        EsignHttpResponse getComponentsInfo = getComponentsInfo(contractInfo.getDocTemplateId());
+        JsonObject getComponentsInfoObject = gson.fromJson(getComponentsInfo.getBody(), JsonObject.class);
+        System.err.println("查询模板详情返回:"+getComponentsInfoObject);
+        SignPositionGroup positionGroup = groupComponentPositions(getComponentsInfoObject);
+        // 个人签署人
+        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());
 
@@ -340,18 +316,29 @@ public class ESignServiceImpl implements IESignService {
         psnInfo.addProperty("psnIDCardNum", familyMembers.getIdentityCard());
         psnInfo.addProperty("psnIDCardType", "CRED_PSN_CH_IDCARD");
         psnSignerInfo.add("psnInfo", psnInfo);
-        signer.add("psnSignerInfo", psnSignerInfo);
-
-        // 添加签署配置和通知配置
-        signer.add("signConfig", buildSignConfig(1, 10));
-        signer.add("noticeConfig", buildNoticeConfig(""));
-    }
 
-    private void setupEnterpriseSigner(JsonObject signer, String orgId) {
-        signer.addProperty("signerType", 1);
+        signer1.add("psnSignerInfo", psnSignerInfo);
+        positionGroup.getCustomer().forEach(position -> {
+            signer1.add("signFields", buildSignFields(contractInfo.getFileId(), position.getX(), position.getY(), 100, 0, 0,false,""));
+        });
+//        signer1.add("signFields", buildSignFields(contractInfo.getFileId(), 100, 200, 96, 100, 100,false,""));
+        // 企业签署人
+        JsonObject signer2 = new JsonObject();
+        signer2.addProperty("signerType", 1);
         JsonObject orgSignerInfo = new JsonObject();
         orgSignerInfo.addProperty("orgId", orgId);
-        signer.add("orgSignerInfo", orgSignerInfo);
+        positionGroup.getMerchant().forEach(position -> {
+            try {
+                signer2.add("signFields", buildSignFields(contractInfo.getFileId(), position.getX(), position.getY(), 100, 0, 0,true,orgAuthorizedSeal(orgId)));
+            } catch (EsignDemoException e) {
+                throw new RuntimeException(e);
+            }
+        });
+//        signer2.add("signFields", buildSignFields(contractInfo.getFileId(), 300, 200, 159, 300, 100,true,orgAuthorizedSeal(orgId)));
+
+        signers.add(signer1);
+        signers.add(signer2);
+        return signers;
     }
 
     /**
@@ -373,9 +360,16 @@ public class ESignServiceImpl implements IESignService {
         return noticeConfig;
     }
 
-
-    private JsonObject buildSignFieldFromComponent(String fileId, int x, int y, int width, int height, boolean autoSign) {
+    /**
+     * 构建签署区域
+     */
+    private JsonArray buildSignFields(String fileId,
+                                      int x, int y,
+                                      int size,
+                                      int dateX, int dateY,boolean autoSign,String signature) {
+        JsonArray signFields = new JsonArray();
         JsonObject field = new JsonObject();
+
         field.addProperty("fileId", fileId);
         field.addProperty("customBizNum", "自定义编码0001");
         field.addProperty("signFieldType", 0);
@@ -386,8 +380,9 @@ public class ESignServiceImpl implements IESignService {
         normalConfig.addProperty("freeMode", false);
         normalConfig.addProperty("movableSignField", false);
         normalConfig.addProperty("psnSealStyles", "0,1");
-        normalConfig.addProperty("signFieldSize", String.valueOf(width)); // 使用组件宽度作为尺寸
+        normalConfig.addProperty("signFieldSize", String.valueOf(size));
         normalConfig.addProperty("signFieldStyle", 1);
+        normalConfig.addProperty("assignedSealId", signature);
 
         // 位置配置
         JsonObject position = new JsonObject();
@@ -396,18 +391,19 @@ public class ESignServiceImpl implements IESignService {
         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", x + width + 10); // 日期默认在签名右侧
-        dateConfig.addProperty("signDatePositionY", y);
+        dateConfig.addProperty("signDatePositionX", dateX);
+        dateConfig.addProperty("signDatePositionY", dateY);
 
         field.add("normalSignFieldConfig", normalConfig);
         field.add("signDateConfig", dateConfig);
-        return field;
-    }
 
+        signFields.add(field);
+        return signFields;
+    }
 
     /**
      * 提取签署流程ID
@@ -518,10 +514,11 @@ public class ESignServiceImpl implements IESignService {
     }
 
     @Override
-    public List<SealInfoDTO> orgOwnSeal(String orgId) {
+    public List<SealInfoDTO> orgOwnSeal(String orgCode) {
+        AppSite appSite = appSiteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, orgCode));
         try {
             // 调用API获取响应
-            EsignHttpResponse response = orgOwnSealList(orgId);
+            EsignHttpResponse response = orgOwnSealList(appSite.getEsignOrgId());
 
             // 解析JSON响应
             JsonObject result = gson.fromJson(response.getBody(), JsonObject.class);
@@ -536,10 +533,62 @@ public class ESignServiceImpl implements IESignService {
             if (!data.has("seals")) {
                 throw new JeecgBootException("响应数据中缺少'seals'字段");
             }
-
-            // 转换数据
-            return gson.fromJson(data.getAsJsonArray("seals"),
-                    new TypeToken<List<SealInfoDTO>>(){}.getType());
+            // 原始数据
+            JsonArray seals = data.getAsJsonArray("seals");
+
+            JsonArray filteredSeals = new JsonArray();
+            for (JsonElement element : seals) {
+                JsonObject seal = element.getAsJsonObject();
+                if ("PUBLIC".equals(seal.get("sealBizType").getAsString())) {
+                    filteredSeals.add(seal);
+                }
+            }
+            List<SealInfoDTO> sealInfoDTOList = gson.fromJson(filteredSeals, new TypeToken<List<SealInfoDTO>>(){}.getType());
+            sealInfoDTOList.forEach(a ->{
+                a.setOrgCode(orgCode);
+                try {
+                    // 调用接口获取授权信息
+                    EsignHttpResponse response1 = orgSealsExternalAuth(appSite.getEsignOrgId(), a.getSealId());
+                    JsonObject result1 = gson.fromJson(response1.getBody(), JsonObject.class);
+
+                    // 检查 data 字段
+                    if (!result1.has("data")) {
+                        log.warn("授权信息中缺少 data 字段");
+                        a.setIsStatus(false);
+                        return;
+                    }
+
+                    JsonObject data1 = result1.getAsJsonObject("data");
+                    if (!data1.has("sealAuthorizedInfos")) {
+                        log.warn("授权信息中缺少 sealAuthorizedInfos 字段");
+                        a.setIsStatus(false);
+                        return;
+                    }
+
+                    // 遍历授权信息列表
+                    JsonArray sealAuthorizedInfos = data1.getAsJsonArray("sealAuthorizedInfos");
+                    boolean isValid = false;
+
+                    for (JsonElement element : sealAuthorizedInfos) {
+                        JsonObject info = element.getAsJsonObject();
+                        String expireReason = info.get("expireReasonDescription").getAsString();
+                        String status = info.get("statusDescription").getAsString();
+
+                        if ("未失效".equals(expireReason) && "正常".equals(status)) {
+                            isValid = true;
+                            break;
+                        }
+                    }
+
+                    // 设置 isStatus 字段
+                    a.setIsStatus(isValid);
+
+                } catch (EsignDemoException | JsonSyntaxException e) {
+                    log.error("处理印章授权状态失败,sealId: {}", a.getSealId(), e);
+                    a.setIsStatus(false);
+                }
+            });
+            return sealInfoDTOList;
 
         } catch (JsonSyntaxException e) {
             throw new JeecgBootException("JSON解析失败: " + e.getMessage(), e);