Explorar o código

暂时提交代码

yousongbo hai 4 días
pai
achega
19d16cf7da

+ 54 - 54
suishenbang-common/src/main/java/com/dgtly/common/utils/http/HttpUtils.java

@@ -449,75 +449,75 @@ public class HttpUtils
         }
         }
         return result.toString();
         return result.toString();
     }
     }
+
+    /**
+     * 向指定 URL 发送HTTPS GET方法的请求(最多重试3次)
+     *
+     * @param url 发送请求的 URL
+     * @return 所代表远程资源的响应结果
+     */
     public static String sendSSLGet(String url)
     public static String sendSSLGet(String url)
     {
     {
-        StringBuilder result = new StringBuilder();
-        BufferedReader in = null;
-        try
-        {
-            String urlNameString = url;
-            log.info("sendSSLGet - {}", urlNameString);
-            SSLContext sc = SSLContext.getInstance("SSL");
-            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
-            URL realUrl = new URL(urlNameString);
+        int maxRetry = 3;
+        Exception lastException = null;
 
 
-            HttpsURLConnection connection = (HttpsURLConnection)realUrl.openConnection();
-            connection.setRequestProperty("accept", "*/*");
-            connection.setRequestProperty("connection", "Keep-Alive");
-            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
-
-            connection.setSSLSocketFactory(sc.getSocketFactory());
-            connection.setHostnameVerifier(new TrustAnyHostnameVerifier());
-
-            connection.connect();
-            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
-            String line;
-            while ((line = in.readLine()) != null)
-            {
-                result.append(line);
-            }
-            log.info("recv - {}", result);
-        }
-        catch(ConnectException e)
+        for (int attempt = 1; attempt <= maxRetry; attempt++)
         {
         {
-            log.error("调用HttpUtils.sendGet ConnectException, url=" + url , e);
+            StringBuilder result = new StringBuilder();
+            BufferedReader in = null;
+            try
+            {
+                log.info("sendSSLGet - {} (第{}次尝试)", url, attempt);
+                SSLContext sc = SSLContext.getInstance("SSL");
+                sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
+                URL realUrl = new URL(url);
 
 
-            throw new BusinessException("调用HttpUtils.sendGet ConnectException, url=" + url  );
-        }
-        catch (SocketTimeoutException e)
-        {
-            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url , e);
+                HttpsURLConnection connection = (HttpsURLConnection)realUrl.openConnection();
+                connection.setRequestProperty("accept", "*/*");
+                connection.setRequestProperty("connection", "Keep-Alive");
+                connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
 
 
-            throw new BusinessException("调用HttpUtils.sendGet SocketTimeoutException, url=" + url  );
+                connection.setSSLSocketFactory(sc.getSocketFactory());
+                connection.setHostnameVerifier(new TrustAnyHostnameVerifier());
 
 
-        }
-        catch (IOException e)
-        {
-            log.error("调用HttpUtils.sendGet IOException, url=" + url, e);
+                connection.setConnectTimeout(10000);   // 连接超时 10s
+                connection.setReadTimeout(30000);      // 读取超时 30s
 
 
-            throw new BusinessException("调用HttpUtils.sendGet IOException, url=" + url  );
-        }
-        catch (Exception e)
-        {
-            log.error("调用HttpsUtil.sendGet Exception, url=" + url , e);
 
 
-            throw new BusinessException("调用HttpUtils.sendGet Exception, url=" + url  );
-        }
-        finally
-        {
-            try
-            {
-                if (in != null)
+                connection.connect();
+                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+                String line;
+                while ((line = in.readLine()) != null)
                 {
                 {
-                    in.close();
+                    result.append(line);
                 }
                 }
+                log.info("sendSSLGet 成功 - url={}, 第{}次尝试", url, attempt);
+                log.info("recv - {}", result);
+                return result.toString();
             }
             }
-            catch (Exception ex)
+            catch (Exception e)
             {
             {
-                log.error("调用in.close Exception, url=" + url , ex);
+                lastException = e;
+                log.warn("sendSSLGet 第{}次尝试失败, url={}, 异常: {}", attempt, url, e.getMessage());
+            }
+            finally
+            {
+                try
+                {
+                    if (in != null)
+                    {
+                        in.close();
+                    }
+                }
+                catch (Exception ex)
+                {
+                    log.error("调用in.close Exception, url=" + url, ex);
+                }
             }
             }
         }
         }
-        return result.toString();
+
+        log.error("sendSSLGet 重试{}次后仍然失败, url={}", maxRetry, url, lastException);
+        throw new BusinessException("调用HttpUtils.sendSSLGet失败,已重试" + maxRetry + "次, url=" + url);
     }
     }
 
 
 
 

+ 75 - 0
suishenbang-system/src/main/java/com/dgtly/system/domain/ESignCorpAuthParam.java

@@ -0,0 +1,75 @@
+package com.dgtly.system.domain;
+
+import lombok.Data;
+
+/**
+ * @FileName: ESignCorpAuthParam
+ * @Description: e签宝发起企业授权书签署任务请求参数
+ *
+ *   接口文档:https://open.esign.cn/doc/opendoc/paas_api/yt92t0zfp3vl3lvg
+ *
+ * @author: auto-generated
+ * @create: 2026-05-13
+ **/
+@Data
+public class ESignCorpAuthParam {
+
+    /**
+     * 机构账号ID(创建机构签署账号接口返回的orgId)
+     * 必填
+     */
+    private String accountId;
+
+    /**
+     * 签署授权书的经办人个人账号ID(创建个人签署账号接口返回的accountId)
+     * 必填
+     * 注意:请传入能为企业操作盖章人员的账号,会绑定 e签宝 SaaS 官网
+     */
+    private String transactorAccountId;
+
+    /**
+     * 授权模式
+     * 1 - 授权至平台(默认,authorizedAccountId 无需传递)
+     * 2 - 授权至经办人(authorizedAccountId 必传)
+     * 注意:模式2默认不可用,需联系 e签宝 技术人员确认开启后使用
+     */
+    private Integer authorizedType;
+
+    /**
+     * 授权至经办人模式下的被授权人个人账号ID(创建个人签署账号接口返回的accountId)
+     * 仅 authorizedType=2 时使用
+     * 注意:若指定授权经办人模式,则被授权人的信息会带到授权书内,
+     *       后续机构手动签署时可通过该被授权人代企业进行签署
+     */
+    private String authorizedAccountId;
+
+    /**
+     * 是否给经办人账号中的联系方式(手机号/邮箱)发送e签宝通知签署链接
+     * true - 发送通知(默认)
+     * false - 不发送通知
+     */
+    private Boolean sendNotice;
+
+    /**
+     * 授权有效期截止时间(截止到当日 23:59:59)
+     * 必填
+     * 格式:yyyyMMdd,类型为 long(如 20271231)
+     * 注意:截止时间会显示到授权协议内,建议授权时间最长不超过3年
+     */
+    private Long validDate;
+
+    /**
+     * 回调通知地址(授权签署结果通知平台,签署完成或者拒签数发回调)
+     */
+    private String notifyUrl;
+
+    /**
+     * 授权签署完成后跳转页面(重定向到平台指定页面)
+     */
+    private String redirectUrl;
+
+    /**
+     * 经销商编码(业务侧字段,非e签宝参数,仅用于写入本地签署状态记录)
+     */
+    private String customeCode;
+}

+ 17 - 0
suishenbang-system/src/main/java/com/dgtly/system/domain/Result.java

@@ -0,0 +1,17 @@
+package com.dgtly.system.domain;
+
+import lombok.Data;
+
+/**
+ * @Author: csz
+ * @Date: 2020/6/7 23:23
+ */
+@Data
+public class Result<T> {
+    private boolean isSuccess;
+    private int code;
+    private String message;
+    private T data;
+
+
+}

+ 45 - 0
suishenbang-system/src/main/java/com/dgtly/system/mapper/EsignCorpAuthSignRecordMapper.java

@@ -0,0 +1,45 @@
+package com.dgtly.system.mapper;
+
+import com.dgtly.system.domain.EsignCorpAuthSignRecord;
+
+/**
+ * @FileName: EsignCorpAuthSignRecordMapper
+ * @Description: e签宝企业授权书签署状态记录 Mapper 接口
+ *
+ * @author: auto-generated
+ * @create: 2026-05-20
+ **/
+public interface EsignCorpAuthSignRecordMapper {
+
+    /**
+     * 新增签署状态记录
+     *
+     * @param record 签署状态记录
+     * @return 影响行数
+     */
+    int insertEsignCorpAuthSignRecord(EsignCorpAuthSignRecord record);
+
+    /**
+     * 根据 authId 查询签署状态记录
+     *
+     * @param authId 授权流程ID
+     * @return 签署状态记录
+     */
+    EsignCorpAuthSignRecord selectByAuthId(String authId);
+
+    /**
+     * 根据经销商编码查询签署状态记录列表
+     *
+     * @param customeCode 经销商编码
+     * @return 签署状态记录列表
+     */
+    EsignCorpAuthSignRecord selectByCustomeCode(String customeCode);
+
+    /**
+     * 根据 authId 更新授权状态
+     *
+     * @param record 仅需 authId + status(+ updateTime 由数据库自动维护)
+     * @return 影响行数
+     */
+    int updateStatusByAuthId(EsignCorpAuthSignRecord record);
+}

+ 46 - 0
suishenbang-system/src/main/java/com/dgtly/system/service/IEsignCorpAuthSignRecordService.java

@@ -0,0 +1,46 @@
+package com.dgtly.system.service;
+
+import com.dgtly.system.domain.EsignCorpAuthSignRecord;
+
+/**
+ * @FileName: IEsignCorpAuthSignRecordService
+ * @Description: e签宝企业授权书签署状态记录 Service 接口
+ *
+ * @author: auto-generated
+ * @create: 2026-05-20
+ **/
+public interface IEsignCorpAuthSignRecordService {
+
+    /**
+     * 新增签署状态记录(status 默认 1=进行中)
+     *
+     * @param record 签署状态记录
+     * @return 影响行数
+     */
+    int insertRecord(EsignCorpAuthSignRecord record);
+
+    /**
+     * 根据 authId 查询记录
+     *
+     * @param authId 授权流程ID
+     * @return 签署状态记录
+     */
+    EsignCorpAuthSignRecord selectByAuthId(String authId);
+
+    /**
+     * 根据经销商编码查询记录列表
+     *
+     * @param customeCode 经销商编码
+     * @return 签署状态记录列表
+     */
+    EsignCorpAuthSignRecord selectByCustomeCode(String customeCode);
+
+    /**
+     * 根据 authId 更新授权状态
+     *
+     * @param authId 授权流程ID
+     * @param status 新状态(1=进行中 2=授权成功 3=授权失败 4=取消授权)
+     * @return 影响行数
+     */
+    int updateStatus(String authId, Integer status);
+}

+ 50 - 0
suishenbang-system/src/main/java/com/dgtly/system/service/impl/EsignCorpAuthSignRecordServiceImpl.java

@@ -0,0 +1,50 @@
+package com.dgtly.system.service.impl;
+
+import com.dgtly.system.domain.EsignCorpAuthSignRecord;
+import com.dgtly.system.mapper.EsignCorpAuthSignRecordMapper;
+import com.dgtly.system.service.IEsignCorpAuthSignRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @FileName: EsignCorpAuthSignRecordServiceImpl
+ * @Description: e签宝企业授权书签署状态记录 Service 实现
+ *
+ * @author: auto-generated
+ * @create: 2026-05-20
+ **/
+@Service
+public class EsignCorpAuthSignRecordServiceImpl implements IEsignCorpAuthSignRecordService {
+
+    @Autowired
+    private EsignCorpAuthSignRecordMapper esignCorpAuthSignRecordMapper;
+
+    /**
+     * 新增签署状态记录,status 若未设置则默认 1(进行中)
+     */
+    @Override
+    public int insertRecord(EsignCorpAuthSignRecord record) {
+        if (record.getStatus() == null) {
+            record.setStatus(1);
+        }
+        return esignCorpAuthSignRecordMapper.insertEsignCorpAuthSignRecord(record);
+    }
+
+    @Override
+    public EsignCorpAuthSignRecord selectByAuthId(String authId) {
+        return esignCorpAuthSignRecordMapper.selectByAuthId(authId);
+    }
+
+    @Override
+    public EsignCorpAuthSignRecord selectByCustomeCode(String customeCode) {
+        return esignCorpAuthSignRecordMapper.selectByCustomeCode(customeCode);
+    }
+
+    @Override
+    public int updateStatus(String authId, Integer status) {
+        EsignCorpAuthSignRecord record = new EsignCorpAuthSignRecord();
+        record.setAuthId(authId);
+        record.setStatus(status);
+        return esignCorpAuthSignRecordMapper.updateStatusByAuthId(record);
+    }
+}

+ 50 - 0
suishenbang-system/src/main/java/com/dgtly/system/util/ResultUtil.java

@@ -0,0 +1,50 @@
+package com.dgtly.system.util;
+
+
+import com.dgtly.system.domain.Result;
+
+/**
+ * @Author: csz
+ * @Date: 2020/6/7 23:28
+ */
+public class ResultUtil {
+
+    public static <V> Result<V> error() {
+        return error(500, "fail");
+    }
+
+
+    public static <V> Result<V> error(int code, String message) {
+        Result<V> result = new Result<V>();
+        result.setSuccess(false);
+        result.setCode(code);
+        result.setMessage(message);
+        return result;
+    }
+
+//    ==============================================================================
+
+    public static <V> Result<V> success() {
+        return success(200, "success");
+    }
+
+    public static <V> Result<V> success(int code, String message) {
+        return success(code, message, null);
+    }
+
+
+    public static <V> Result<V> success(V data) {
+        return success(200, "success", data);
+    }
+
+
+    public static <V> Result<V> success(int code, String message, V data) {
+        Result<V> result = new Result<V>();
+        result.setSuccess(true);
+        result.setCode(code);
+        result.setMessage(message);
+        result.setData(data);
+        return result;
+    }
+
+}

+ 70 - 0
suishenbang-system/src/main/resources/mapper/system/EsignCorpAuthSignRecordMapper.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.dgtly.system.mapper.EsignCorpAuthSignRecordMapper">
+
+    <resultMap type="com.dgtly.system.domain.EsignCorpAuthSignRecord" id="EsignCorpAuthSignRecordResult">
+        <id     property="id"          column="id"           />
+        <result property="authId"       column="auth_id"      />
+        <result property="orgId"        column="org_id"       />
+        <result property="customeCode"  column="custome_code" />
+        <result property="creator"      column="creator"      />
+        <result property="status"       column="status"       />
+        <result property="createTime"   column="create_time"  />
+        <result property="updateTime"   column="update_time"  />
+    </resultMap>
+
+    <!-- 通用查询列 -->
+    <sql id="selectEsignCorpAuthSignRecordVo">
+        select id, auth_id, org_id, custome_code, creator, status, create_time, update_time
+        from esign_corp_auth_sign_record
+    </sql>
+
+    <!-- 新增 -->
+    <insert id="insertEsignCorpAuthSignRecord" parameterType="com.dgtly.system.domain.EsignCorpAuthSignRecord"
+            useGeneratedKeys="true" keyProperty="id">
+        insert into esign_corp_auth_sign_record
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="authId      != null and authId      != ''">auth_id,</if>
+            <if test="orgId       != null and orgId       != ''">org_id,</if>
+            <if test="customeCode != null and customeCode != ''">custome_code,</if>
+            <if test="creator     != null and creator     != ''">creator,</if>
+            <if test="status      != null">status,</if>
+            create_time,
+            update_time
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="authId      != null and authId      != ''">#{authId},</if>
+            <if test="orgId       != null and orgId       != ''">#{orgId},</if>
+            <if test="customeCode != null and customeCode != ''">#{customeCode},</if>
+            <if test="creator     != null and creator     != ''">#{creator},</if>
+            <if test="status      != null">#{status},</if>
+            now(),
+            now()
+        </trim>
+    </insert>
+
+    <!-- 根据 authId 查询 -->
+    <select id="selectByAuthId" parameterType="String" resultMap="EsignCorpAuthSignRecordResult">
+        <include refid="selectEsignCorpAuthSignRecordVo"/>
+        where auth_id = #{authId}
+        limit 1
+    </select>
+
+    <!-- 根据 custome_code 查询(返回列表,按创建时间倒序) -->
+    <select id="selectByCustomeCode" parameterType="String" resultMap="EsignCorpAuthSignRecordResult">
+        <include refid="selectEsignCorpAuthSignRecordVo"/>
+        where custome_code = #{customeCode}
+        order by create_time desc limit 1
+    </select>
+
+    <!-- 根据 authId 更新状态 -->
+    <update id="updateStatusByAuthId" parameterType="com.dgtly.system.domain.EsignCorpAuthSignRecord">
+        update esign_corp_auth_sign_record
+        set status      = #{status},
+            update_time = now()
+        where auth_id = #{authId}
+    </update>
+
+</mapper>

+ 131 - 4
suishenbang-wxportal/suishenbang-wxportal-api/src/main/java/com/dgtly/wxportal/controller/EsignController.java

@@ -1,5 +1,6 @@
 package com.dgtly.wxportal.controller;
 package com.dgtly.wxportal.controller;
 
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.dgtly.common.annotation.ApiPassToken;
 import com.dgtly.common.annotation.ApiPassToken;
 import com.dgtly.common.config.ServerConfig;
 import com.dgtly.common.config.ServerConfig;
@@ -10,6 +11,7 @@ import com.dgtly.common.utils.StringUtils;
 import com.dgtly.system.domain.*;
 import com.dgtly.system.domain.*;
 import com.dgtly.system.service.*;
 import com.dgtly.system.service.*;
 import com.dgtly.system.util.AuthType;
 import com.dgtly.system.util.AuthType;
+import com.dgtly.system.util.ResultUtil;
 import com.dgtly.wxportal.config.ESignConfig;
 import com.dgtly.wxportal.config.ESignConfig;
 import com.dgtly.wxportal.domain.ESignUpPDFModal;
 import com.dgtly.wxportal.domain.ESignUpPDFModal;
 import com.dgtly.wxportal.domain.OrderFile;
 import com.dgtly.wxportal.domain.OrderFile;
@@ -21,10 +23,7 @@ import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.tomcat.util.digester.ArrayStack;
 import org.apache.tomcat.util.digester.ArrayStack;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
@@ -675,6 +674,7 @@ public class EsignController extends ApiBaseController {
         SysUser user = userService.selectUserById(userId);
         SysUser user = userService.selectUserById(userId);
 //        CustomersExt customersExt = obj.parseBean(CustomersExt.class);
 //        CustomersExt customersExt = obj.parseBean(CustomersExt.class);
         CustomersExt customersExt = customersExtService.selectCustomersExtById(user.getSysUserExt().getOrgCode());
         CustomersExt customersExt = customersExtService.selectCustomersExtById(user.getSysUserExt().getOrgCode());
+        log.info("11111111111:{}", JSON.toJSON(customersExt));
         if (customersExt==null){
         if (customersExt==null){
             customersExt = new CustomersExt();
             customersExt = new CustomersExt();
             if (user.getAccountId()!=null&&!user.getAccountId().equals("")) {
             if (user.getAccountId()!=null&&!user.getAccountId().equals("")) {
@@ -682,8 +682,11 @@ public class EsignController extends ApiBaseController {
             }else {
             }else {
                 return AjaxResult.error(201,"个人未注册");
                 return AjaxResult.error(201,"个人未注册");
             }
             }
+            log.info("sss{}",JSON.toJSON(user));
+            log.info("fff{}",JSON.toJSON(user.getSysUserExt().getOrgCode()));
             customersExt.setChainsCode(user.getSysUserExt().getOrgCode());
             customersExt.setChainsCode(user.getSysUserExt().getOrgCode());
         }
         }
+        log.info("222222222222:{}", JSON.toJSON(customersExt));
         //判断是否注册
         //判断是否注册
         if (customersExt.getOrgId()!=null&&!customersExt.getOrgId().equals("")){//已经注册
         if (customersExt.getOrgId()!=null&&!customersExt.getOrgId().equals("")){//已经注册
             //判断是否认证
             //判断是否认证
@@ -706,6 +709,7 @@ public class EsignController extends ApiBaseController {
                     if (ecustomersExt!=null){
                     if (ecustomersExt!=null){
                         ecustomersExt.setOrgId(orgId);
                         ecustomersExt.setOrgId(orgId);
                         /*修改企业id*/
                         /*修改企业id*/
+
                         customersExtService.updateCustomersExt(ecustomersExt);
                         customersExtService.updateCustomersExt(ecustomersExt);
                     }else {
                     }else {
                         ecustomersExt = new CustomersExt();
                         ecustomersExt = new CustomersExt();
@@ -881,4 +885,127 @@ public class EsignController extends ApiBaseController {
             return AjaxResult.error(result.getString("message"));
             return AjaxResult.error(result.getString("message"));
         }
         }
     }
     }
+
+    /**
+     * 发起企业授权书签署任务
+     *
+     * @param param 请求参数(JSON Body)
+     * @return Result,data 中包含 taskId 和 signUrl
+     *
+     * 请求示例:
+     * POST /order/esign/corpAuthSign
+     * {
+     *   "accountId"           : "机构账号ID(创建机构签署账号接口返回的orgId)",
+     *   "transactorAccountId" : "经办人个人账号ID(创建个人签署账号接口返回的accountId)",
+     *   "authorizedType"      : 1,
+     *   "sendNotice"          : true,
+     *   "validDate"           : 20271231,
+     *   "notifyUrl"           : "https://your-domain.com/esign/notify",
+     *   "redirectUrl"         : "https://your-domain.com/esign/redirect"
+     * }
+     *
+     * 参数说明:
+     *   accountId            必填,机构账号ID
+     *   transactorAccountId  必填,经办人个人账号ID
+     *   authorizedType       可选,1=授权至平台(默认),2=授权至经办人
+     *   authorizedAccountId  可选,被授权人账号ID(authorizedType=2 时必填)
+     *   sendNotice           可选,是否发送通知,默认 true
+     *   validDate            必填,授权有效期截止时间(yyyyMMdd格式,如 20271231)
+     *   notifyUrl            可选,授权结果回调通知地址
+     *   redirectUrl          可选,签署完成后跳转页面
+     */
+    @PostMapping("/corpAuthSign")
+    @ResponseBody
+    public Result corpAuthSign(@RequestBody ESignCorpAuthParam param) {
+        try {
+            return eSignService.initiateCorpAuthSign(param);
+        } catch (IOException e) {
+            log.error("[ESign] 发起企业授权书签署任务异常, accountId={}", param != null ? param.getAccountId() : "null", e);
+            return ResultUtil.error(500,"发起企业授权书签署任务异常:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 获取授权流程签署URL
+     *
+     * 接口:POST /v1/signAuthApi/signUrl
+     *
+     * 请求参数:
+     *   authId      String  是   授权流程ID
+     *   needLogin   boolean 否   是否需要登录打开链接,默认 true(true=需要登录,false=免登录)
+     *   clientType  String  否   客户端类型:H5(移动端)/ PC(PC端)/ ALL(自动适配,默认)
+     *   redirectUrl String  否   授权签署完成后跳转页面
+     *   appScheme   String  否   AppScheme,用于唤起 App,示例:esign://demo/signBack
+     *
+     * 响应 data:
+     *   shortUrl  String  授权流程签署短链接(链接90天内有效)
+     *   longUrl   String  授权流程签署长链接(链接90天内有效)
+     */
+    @ApiOperation(value = "获取授权流程签署URL",
+            notes = "参数:{'authId':'xxx','needLogin':true,'clientType':'ALL','redirectUrl':'xxx','appScheme':'xxx'}" +
+                    "\n authId:授权流程ID(必填)" +
+                    "\n needLogin:是否需要登录打开链接,默认true(true=需要登录,false=免登录)" +
+                    "\n clientType:客户端类型,H5/PC/ALL(默认ALL)" +
+                    "\n redirectUrl:授权签署完成后跳转页面" +
+                    "\n appScheme:AppScheme,用于唤起App,示例:esign://demo/signBack")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "params", paramType = "body")
+    })
+    @PostMapping("/getSignUrl")
+    @ResponseBody
+    public Result getSignUrl() {
+        ParameterObject obj = getParameterObject();
+        obj.checkParameterNotNull("authId");
+        String authId = obj.getString("authId");
+        Boolean needLogin = obj.getBoolean("needLogin");
+        String clientType = obj.getString("clientType");
+        String redirectUrl = obj.getString("redirectUrl");
+        String appScheme = obj.getString("appScheme");
+        try {
+            return eSignService.getSignUrl(authId, needLogin, clientType, redirectUrl, appScheme);
+        } catch (IOException e) {
+            log.error("[ESign] 获取授权流程签署URL异常, authId={}", authId, e);
+            return ResultUtil.error(500, "获取授权流程签署URL异常:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 查询授权结果
+     *
+     * 接口:GET /v1/signAuthApi/queryAuthResult?authId=XXX
+     *
+     * 请求参数:
+     *   authId  String  是  授权流程ID(Query 参数)
+     *
+     * 响应 data:
+     *   authId             String  授权流程ID
+     *   status             int     授权状态:1=进行中 2=授权成功 3=授权失败 4=取消授权
+     *   failReason         String  授权说明(授权失败时返回原因)
+     *   effectiveStartTime long    授权生效时间(格式 yyyyMMdd,如 20260101)
+     *   effectiveEndTime   long    授权失效时间(格式 yyyyMMdd,如 20260101)
+     *   authDownloadUrl    String  授权书下载链接(有效期60分钟,仅 status=2 授权成功时返回)
+     */
+    @ApiOperation(value = "查询授权结果",
+            notes = "参数:{'authId':'xxx'}" +
+                    "\n authId:授权流程ID(必填)" +
+                    "\n 响应 data.status:1=进行中 2=授权成功 3=授权失败 4=取消授权" +
+                    "\n 响应 data.authDownloadUrl:授权书下载链接(有效期60分钟,仅授权成功时返回)")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "params", paramType = "body")
+    })
+    @PostMapping("/queryAuthResult")
+    @ResponseBody
+    public Result queryAuthResult() {
+        ParameterObject obj = getParameterObject();
+        String authId = obj.getString("authId") == null ? "" : obj.getString("authId");
+        obj.checkParameterNotNull("customeCode");
+        String customeCode = obj.getString("customeCode");
+        try {
+            return eSignService.queryAuthResult(authId,customeCode);
+        } catch (IOException e) {
+            log.error("[ESign] 查询授权结果异常, authId={}", authId, e);
+            return ResultUtil.error(500, "查询授权结果异常:" + e.getMessage());
+        }
+    }
+
 }
 }

+ 33 - 0
suishenbang-wxportal/suishenbang-wxportal-common/src/main/java/com/dgtly/wxportal/service/ESignService.java

@@ -2,10 +2,13 @@ package com.dgtly.wxportal.service;
 
 
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.dgtly.system.domain.CustomersExt;
 import com.dgtly.system.domain.CustomersExt;
+import com.dgtly.system.domain.ESignCorpAuthParam;
+import com.dgtly.system.domain.Result;
 import com.dgtly.system.domain.SysUser;
 import com.dgtly.system.domain.SysUser;
 import com.dgtly.wxportal.domain.ESignUpPDFModal;
 import com.dgtly.wxportal.domain.ESignUpPDFModal;
 import com.dgtly.wxportal.domain.OrderFile;
 import com.dgtly.wxportal.domain.OrderFile;
 
 
+import java.io.IOException;
 import java.util.Map;
 import java.util.Map;
 
 
 /**
 /**
@@ -104,4 +107,34 @@ public interface ESignService {
      *
      *
      */
      */
     JSONObject delOrganizations (String orgId);
     JSONObject delOrganizations (String orgId);
+
+  /**
+   * @description: 发起企业授权书签署任务(线上)
+   * @param param 请求参数
+   * @return com.dgtis.commons.exception.model.Result
+   * @author auto-generated
+   * @date 2026-05-13
+   */
+  Result initiateCorpAuthSign(ESignCorpAuthParam param) throws IOException;
+
+  /**
+   * @description: 获取授权流程签署URL(/v1/signAuthApi/signUrl)
+   * @param authId      授权流程ID(必填)
+   * @param needLogin   是否需要登录打开链接,默认 true
+   * @param clientType  客户端类型:H5 / PC / ALL(默认 ALL)
+   * @param redirectUrl 签署完成后跳转页面
+   * @param appScheme   AppScheme,用于唤起 App
+   * @return Result,data 中包含 shortUrl 和 longUrl
+   * @date 2026-05-19
+   */
+  Result getSignUrl(String authId, Boolean needLogin, String clientType, String redirectUrl, String appScheme) throws IOException;
+
+  /**
+   * @description: 查询授权结果(/v1/signAuthApi/queryAuthResult)
+   * @param authId 授权流程ID(必填)
+   * @return Result,data 中包含 authId / status / failReason / effectiveStartTime / effectiveEndTime / authDownloadUrl
+   *   status: 1=进行中 2=授权成功 3=授权失败 4=取消授权
+   * @date 2026-05-19
+   */
+  Result queryAuthResult(String authId,String customeCode) throws IOException;
 }
 }

+ 252 - 0
suishenbang-wxportal/suishenbang-wxportal-common/src/main/java/com/dgtly/wxportal/service/impl/ESignServiceImpl.java

@@ -1,10 +1,17 @@
 package com.dgtly.wxportal.service.impl;
 package com.dgtly.wxportal.service.impl;
 
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.dgtly.system.domain.CustomersExt;
 import com.dgtly.system.domain.CustomersExt;
+import com.dgtly.system.domain.ESignCorpAuthParam;
+import com.dgtly.system.domain.EsignCorpAuthSignRecord;
+import com.dgtly.system.domain.Result;
+import com.dgtly.system.util.HttpUtil;
+import com.dgtly.system.util.ResultUtil;
 import com.dgtly.wxportal.domain.EReceivingNote;
 import com.dgtly.wxportal.domain.EReceivingNote;
 import com.dgtly.system.domain.SysUser;
 import com.dgtly.system.domain.SysUser;
 import com.dgtly.system.service.ICustomersExtService;
 import com.dgtly.system.service.ICustomersExtService;
+import com.dgtly.system.service.IEsignCorpAuthSignRecordService;
 import com.dgtly.wxportal.domain.ESignUpPDFModal;
 import com.dgtly.wxportal.domain.ESignUpPDFModal;
 import com.dgtly.wxportal.domain.OrderFile;
 import com.dgtly.wxportal.domain.OrderFile;
 import com.dgtly.wxportal.domain.OrderSelfNote;
 import com.dgtly.wxportal.domain.OrderSelfNote;
@@ -21,6 +28,7 @@ import com.dgtly.wxportal.utils.pdf.Watermark;
 import com.itextpdf.text.Document;
 import com.itextpdf.text.Document;
 import com.itextpdf.text.PageSize;
 import com.itextpdf.text.PageSize;
 import com.itextpdf.text.pdf.PdfWriter;
 import com.itextpdf.text.pdf.PdfWriter;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +36,7 @@ import org.springframework.stereotype.Service;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.Date;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
@@ -58,6 +67,9 @@ public class ESignServiceImpl implements ESignService {
     private ESignConfig eSignConfig;
     private ESignConfig eSignConfig;
     @Autowired
     @Autowired
     private IEReceivingNoteService iMetaHanaSalesOrderService;
     private IEReceivingNoteService iMetaHanaSalesOrderService;
+    @Autowired
+    private IEsignCorpAuthSignRecordService esignCorpAuthSignRecordService;
+
 
 
     @Override
     @Override
     public ESignUpPDFModal upload(String orderId,String tmsShipNumber,String customerCode,String customerName,String userName) {
     public ESignUpPDFModal upload(String orderId,String tmsShipNumber,String customerCode,String customerName,String userName) {
@@ -176,6 +188,7 @@ public class ESignServiceImpl implements ESignService {
     @Override
     @Override
     public CustomersExt createThirdParty(CustomersExt customersExt) {
     public CustomersExt createThirdParty(CustomersExt customersExt) {
         JSONObject json = new JSONObject();
         JSONObject json = new JSONObject();
+        log.info("333333333333:{}", JSON.toJSON(customersExt));
         int isok = 1;
         int isok = 1;
         json.put("thirdPartyUserId",customersExt.getChainsCode());
         json.put("thirdPartyUserId",customersExt.getChainsCode());
         json.put("creator",customersExt.getCreator());
         json.put("creator",customersExt.getCreator());
@@ -476,4 +489,243 @@ public class ESignServiceImpl implements ESignService {
         return result;
         return result;
     }
     }
 
 
+    /**
+     * 发起企业授权书签署任务
+     *
+     * <pre>
+     * 请求示例:
+     * POST https://openapi.esign.cn/v3/org-auth/corp-auth-sign/tasks
+     * {
+     *   "accountId"           : "机构账号ID",
+     *   "transactorAccountId" : "经办人个人账号ID",
+     *   "authorizedType"      : 1,
+     *   "sendNotice"          : true,
+     *   "validDate"           : 20271231,
+     *   "notifyUrl"           : "https://your-domain.com/esign/notify",
+     *   "redirectUrl"         : "https://your-domain.com/esign/redirect"
+     * }
+     *
+     * 成功响应示例:
+     * {
+     *   "code"    : 0,
+     *   "message" : "成功",
+     *   "data"    : {
+     *     "taskId"  : "xxx",
+     *     "signUrl" : "https://..."
+     *   }
+     * }
+     * </pre>
+     *
+     * @param param 请求参数
+     * @return Result
+     */
+    @Override
+    public Result initiateCorpAuthSign(ESignCorpAuthParam param) throws IOException {
+        // 1. 参数基础校验
+        if (param == null) {
+            return ResultUtil.error(500, "请求参数不能为空");
+        }
+        if (StringUtils.isBlank(param.getAccountId())) {
+            return ResultUtil.error(500, "机构账号ID(accountId)不能为空");
+        }
+//        if (StringUtils.isBlank(param.getTransactorAccountId())) {
+//            return ResultUtil.error(500, "经办人账号ID(transactorAccountId)不能为空");
+//        }
+        if (param.getValidDate() == null) {
+            return ResultUtil.error(500, "授权有效期截止时间(validDate)不能为空");
+        }
+        // authorizedType=2 时 authorizedAccountId 必传
+        if (param.getAuthorizedType() != null && param.getAuthorizedType() == 2
+                && StringUtils.isBlank(param.getAuthorizedAccountId())) {
+            return ResultUtil.error(500, "授权至经办人模式(authorizedType=2)时,被授权人账号ID(authorizedAccountId)不能为空");
+        }
+
+        // 2. 构建请求体
+        JSONObject json = new JSONObject();
+        json.put("accountId",           param.getAccountId());
+        json.put("transactorAccountId", param.getTransactorAccountId());
+
+        if (param.getAuthorizedType() != null) {
+            json.put("authorizedType", param.getAuthorizedType());
+        }
+        if (StringUtils.isNotBlank(param.getAuthorizedAccountId())) {
+            json.put("authorizedAccountId", param.getAuthorizedAccountId());
+        }
+        // sendNotice 默认 true,仅显式传 false 时才覆盖
+        if (param.getSendNotice() != null) {
+            json.put("sendNotice", param.getSendNotice());
+        }
+        json.put("validDate", param.getValidDate());
+
+        if (StringUtils.isNotBlank(param.getNotifyUrl())) {
+            json.put("notifyUrl", param.getNotifyUrl());
+        }
+        if (StringUtils.isNotBlank(param.getRedirectUrl())) {
+            json.put("redirectUrl", param.getRedirectUrl());
+        }
+        json.put("sendNotice",false);
+
+        log.info("[ESign] 发起企业授权书签署任务, url={}, accountId={}, transactorAccountId={}",
+                ESignUrl.createEsignAuthUrl, param.getAccountId(), param.getTransactorAccountId());
+
+        // 4. 发起 HTTP 请求
+        JSONObject responseJson = eSignHttpUtil.doPostGetJson(ESignUrl.createEsignAuthUrl,json);
+        log.info("[ESign] 企业授权书签署任务响应, response={}", responseJson);
+
+        // 5. 解析响应
+        if (responseJson == null) {
+            return ResultUtil.error(500, "e签宝接口返回为空");
+        }
+        if (responseJson == null) {
+            return ResultUtil.error(500, "e签宝接口响应解析失败");
+        }
+
+        Integer code = responseJson.getInteger("code");
+        String message = responseJson.getString("message");
+
+        if (code == null || code != 0) {
+            log.warn("[ESign] 企业授权书签署任务失败, code={}, message={}", code, message);
+            return ResultUtil.error(500, "发起企业授权书签署任务失败:" + message);
+        }
+
+        // 6. 成功,返回 data(含 taskId / signUrl 等)
+        Object data = responseJson.get("data");
+
+        // 7. 将 authId 写入本地签署状态记录表
+        try {
+            JSONObject dataJson = responseJson.getJSONObject("data");
+            String authId = dataJson != null ? dataJson.getString("authId") : null;
+            if (StringUtils.isNotBlank(authId)) {
+                EsignCorpAuthSignRecord record = new EsignCorpAuthSignRecord();
+                record.setAuthId(authId);
+                record.setOrgId(param.getAccountId());
+                record.setCreator(param.getTransactorAccountId());
+                record.setCustomeCode(param.getCustomeCode());
+                record.setStatus(1); // 1=进行中
+                esignCorpAuthSignRecordService.insertRecord(record);
+                log.info("[ESign] 签署状态记录已写入, authId={}, orgId={}, customeCode={}",
+                        authId, param.getAccountId(), param.getCustomeCode());
+            } else {
+                log.warn("[ESign] 发起成功但 data 中未找到 authId,跳过写入签署状态记录, data={}", dataJson);
+            }
+        } catch (Exception e) {
+            // 写入记录失败不影响主流程,仅记录日志
+            log.error("[ESign] 写入签署状态记录失败, accountId={}", param.getAccountId(), e);
+        }
+
+        return ResultUtil.success(data);
+    }
+
+    /**
+     * 获取授权流程签署URL
+     *
+     * <pre>
+     * POST /v1/signAuthApi/signUrl
+     * 请求参数:
+     *   authId      String  是   授权流程ID
+     *   needLogin   boolean 否   是否需要登录打开链接,默认 true
+     *   clientType  String  否   客户端类型:H5 / PC / ALL(默认 ALL)
+     *   redirectUrl String  否   签署完成后跳转页面
+     *   appScheme   String  否   AppScheme,用于唤起 App
+     *
+     * 响应:
+     *   code     int    业务码,0 表示成功
+     *   message  String 业务信息
+     *   data:
+     *     shortUrl String 授权流程签署短链接(90天有效)
+     *     longUrl  String 授权流程签署长链接(90天有效)
+     * </pre>
+     */
+    @Override
+    public Result getSignUrl(String authId, Boolean needLogin, String clientType,
+                             String redirectUrl, String appScheme) throws IOException {
+        if (StringUtils.isBlank(authId)) {
+            return ResultUtil.error(500, "授权流程ID(authId)不能为空");
+        }
+
+        // 构建请求体
+        JSONObject json = new JSONObject();
+        json.put("authId", authId);
+        if (needLogin != null) {
+            json.put("needLogin", needLogin);
+        }
+        if (StringUtils.isNotBlank(clientType)) {
+            json.put("clientType", clientType.toUpperCase());
+        }
+        if (StringUtils.isNotBlank(redirectUrl)) {
+            json.put("redirectUrl", redirectUrl);
+        }
+        if (StringUtils.isNotBlank(appScheme)) {
+            json.put("appScheme", appScheme);
+        }
+
+        log.info("[ESign] 获取授权流程签署URL, authId={}", authId);
+
+        JSONObject responseJson = eSignHttpUtil.doPostGetJson(ESignUrl.getSignUrl, json);
+        log.info("[ESign] 获取授权流程签署URL响应, response={}", responseJson);
+
+        if (responseJson == null) {
+            return ResultUtil.error(500, "e签宝接口返回为空");
+        }
+
+        Integer code = responseJson.getInteger("code");
+        String message = responseJson.getString("message");
+
+        if (code == null || code != 0) {
+            log.warn("[ESign] 获取授权流程签署URL失败, code={}, message={}", code, message);
+            return ResultUtil.error(500, "获取授权流程签署URL失败:" + message);
+        }
+
+        Object data = responseJson.get("data");
+        return ResultUtil.success(data);
+    }
+
+    /**
+     * 查询授权结果
+     *
+     * <pre>
+     * GET /v1/signAuthApi/queryAuthResult?authId={authId}
+     *
+     * 响应 data 字段:
+     *   authId             String  授权流程ID
+     *   status             int     授权状态:1=进行中 2=授权成功 3=授权失败 4=取消授权
+     *   failReason         String  授权说明(授权失败时返回原因)
+     *   effectiveStartTime long    授权生效时间(格式 yyyyMMdd)
+     *   effectiveEndTime   long    授权失效时间(格式 yyyyMMdd)
+     *   authDownloadUrl    String  授权书下载链接(有效期60分钟,仅 status=2 时返回)
+     * </pre>
+     */
+    @Override
+    public Result queryAuthResult(String authId,String customeCode) throws IOException {
+        EsignCorpAuthSignRecord esignCorpAuthSignRecord =esignCorpAuthSignRecordService.selectByCustomeCode(customeCode);
+        if (esignCorpAuthSignRecord == null){
+            return ResultUtil.error(500, "e签宝暂未签署授权");
+        }else {
+            if (StringUtils.isEmpty(authId)){
+                authId = esignCorpAuthSignRecord.getAuthId();
+            }
+        }
+
+        log.info("[ESign] 查询授权结果, authId={}", authId);
+
+        // GET 请求,authId 作为 query 参数拼入 URL(枚举 URL 含 %s 占位符)
+        JSONObject responseJson = eSignHttpUtil.doGetGetJson(ESignUrl.queryAuthResult, new JSONObject(), authId);
+        log.info("[ESign] 查询授权结果响应, response={}", responseJson);
+
+        if (responseJson == null) {
+            return ResultUtil.error(500, "e签宝接口返回为空");
+        }
+
+        Integer code = responseJson.getInteger("code");
+        String message = responseJson.getString("message");
+
+        if (code == null || code != 0) {
+            log.warn("[ESign] 查询授权结果失败, code={}, message={}", code, message);
+            return ResultUtil.error(500, "查询授权结果失败:" + message);
+        }
+
+        Object data = responseJson.get("data");
+        return ResultUtil.success(data);
+    }
+
 }
 }

+ 6 - 0
suishenbang-wxportal/suishenbang-wxportal-common/src/main/java/com/dgtly/wxportal/utils/ESign/ESignUrl.java

@@ -48,6 +48,12 @@ public enum ESignUrl {
     ,getAccountIdByThirdId("/v1/accounts/getByThirdId?thirdPartyUserId=%s")
     ,getAccountIdByThirdId("/v1/accounts/getByThirdId?thirdPartyUserId=%s")
     //E签宝企业信息查询
     //E签宝企业信息查询
     ,getOrgIdByThirdId("/v1/organizations/getByThirdId?thirdPartyUserId=%s")
     ,getOrgIdByThirdId("/v1/organizations/getByThirdId?thirdPartyUserId=%s")
+    //E签宝发起企业授权书签署任务 URI
+    ,createEsignAuthUrl("/v1/signAuthApi/online")
+    //E签宝获取授权流程签署URL
+    ,getSignUrl("/v1/signAuthApi/signUrl")
+    //E签宝查询授权结果
+    ,queryAuthResult("/v1/signAuthApi/queryAuthResult?authId=%s")
     //公司信息修改
     //公司信息修改
     ,updateThirdParty("/v1/organizations/%s")
     ,updateThirdParty("/v1/organizations/%s")
     //设置静默签署
     //设置静默签署