Browse Source

中融爱融实名认证和签合同功能

zhou.xiaoning 1 năm trước cách đây
mục cha
commit
4ac6705880

+ 37 - 37
config/config.go

@@ -441,43 +441,43 @@ func (c *ServiceConfig) Init(path string) error {
 	}
 
 	// 爱签配置
-	// asignsettings := root.SelectElements("Asign")
-	// for _, setting := range asignsettings {
-	// 	// url
-	// 	url := setting.SelectElement("Url")
-	// 	if url == nil {
-	// 		return errors.New("read asign url failed")
-	// 	}
-	// 	SerCfg.AsignCfg.Url = url.SelectAttrValue("value", "")
-
-	// 	// AppId
-	// 	appId := setting.SelectElement("AppId")
-	// 	if appId == nil {
-	// 		return errors.New("read asign AppId failed")
-	// 	}
-	// 	SerCfg.AsignCfg.AppId = appId.SelectAttrValue("value", "")
-
-	// 	// 私钥
-	// 	privateKey := setting.SelectElement("PrivateKey")
-	// 	if privateKey == nil {
-	// 		return errors.New("read asign PrivateKey failed")
-	// 	}
-	// 	SerCfg.AsignCfg.PrivateKey = privateKey.SelectAttrValue("value", "")
-
-	// 	// 合同签署回调通知URL
-	// 	notifyUrl := setting.SelectElement("NotifyUrl")
-	// 	if notifyUrl == nil {
-	// 		return errors.New("read asign notifyUrl failed")
-	// 	}
-	// 	SerCfg.AsignCfg.NotifyUrl = notifyUrl.SelectAttrValue("value", "")
-
-	// 	// 应用的唯一标识
-	// 	openApiUrl := setting.SelectElement("OpenApiUrl")
-	// 	if openApiUrl == nil {
-	// 		return errors.New("read asgin openApiUrl failed")
-	// 	}
-	// 	SerCfg.AsignCfg.OpenApiUrl = openApiUrl.SelectAttrValue("value", "")
-	// }
+	asignsettings := root.SelectElements("Asign")
+	for _, setting := range asignsettings {
+		// url
+		url := setting.SelectElement("Url")
+		if url == nil {
+			return errors.New("read asign url failed")
+		}
+		SerCfg.AsignCfg.Url = url.SelectAttrValue("value", "")
+
+		// AppId
+		appId := setting.SelectElement("AppId")
+		if appId == nil {
+			return errors.New("read asign AppId failed")
+		}
+		SerCfg.AsignCfg.AppId = appId.SelectAttrValue("value", "")
+
+		// 私钥
+		privateKey := setting.SelectElement("PrivateKey")
+		if privateKey == nil {
+			return errors.New("read asign PrivateKey failed")
+		}
+		SerCfg.AsignCfg.PrivateKey = privateKey.SelectAttrValue("value", "")
+
+		// 合同签署回调通知URL
+		notifyUrl := setting.SelectElement("NotifyUrl")
+		if notifyUrl == nil {
+			return errors.New("read asign notifyUrl failed")
+		}
+		SerCfg.AsignCfg.NotifyUrl = notifyUrl.SelectAttrValue("value", "")
+
+		// 应用的唯一标识
+		openApiUrl := setting.SelectElement("OpenApiUrl")
+		if openApiUrl == nil {
+			return errors.New("read asgin openApiUrl failed")
+		}
+		SerCfg.AsignCfg.OpenApiUrl = openApiUrl.SelectAttrValue("value", "")
+	}
 
 	return nil
 }

+ 14 - 7
config/config.xml

@@ -13,11 +13,11 @@
     <DbAddress value="192.168.31.88"/>
     <DbName value="orcl"/>
     <DbPort value="1521"/>
-    <DbUser value="mtp2_test204"/>
+    <DbUser value="mtp2_test134"/>
     <DbPwd value="muchinfo"/>
   </DbSetting>
   <RedisSetting>
-    <Address value="192.168.31.204"/>
+    <Address value="192.168.31.134"/>
     <Port value="5007"/>
     <Timeout value="3"/>
     <ConnNum value="1"/>
@@ -25,11 +25,11 @@
     <Pwd value=""/>
   </RedisSetting>
   <MqSetting>
-    <Url value="amqp://guest:guest@192.168.31.204:5020/test"/>
+    <Url value="amqp://guest:guest@192.168.31.134:5020/test"/>
     <Exchange value="entry"/>
   </MqSetting>
   <MongoDBSetting>
-    <HostName value="192.168.31.204"/>
+    <HostName value="192.168.31.134"/>
     <Port value="5025"/>
     <DBName value="HistoryQuote"/>
     <Username value="quote_test01"/>
@@ -38,12 +38,12 @@
   <MySQLSetting>
     <Host value="192.168.30.72"/>
     <Port value="3306"/>
-    <DBName value="historyquote_test204"/>
-    <Username value="quote_test204"/>
+    <DBName value="historyquote_test134"/>
+    <Username value="quote_test134"/>
     <Password value="123456"/>
   </MySQLSetting>
   <Tencent>
-    <Enabled value="0"/>
+    <Enabled value="1"/>
     <SecretId value="AKyDwiyUUckpkct4igUy8lsS7SEqR6c7yR"/>
     <SecretKey value="SKwvG74cbV3OrAiJdjU5k4507vZwNYDbwT"/>
     <EndPoint value="essbasic.test.ess.tencent.cn"/>
@@ -54,4 +54,11 @@
     <SignToken value="D586D270A51448179277A11729F37D3E"/>
     <SignKey value="8774F484EA294C1E829EA6E2D7F99123"/>
   </Tencent>
+  <Asign>
+    <Url value="https://prev.asign.cn"/>
+    <AppId value="896210645"/>
+    <PrivateKey value="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqmByEbXbqqq+FYxD1+mJzqrVxG/7xNF3iZJV9q0PqOVwWPEtND8nNuB2FeAwHc5+W7dZwXheVaQqWXvV6lnWp3KaQ9S4CbeOX7zKKF0j42JMj4Adknid9X6OlULZeVoXcQsdQ2h9xpfJhwLka4aOX5p1eP6WocXMrkAVRXEA8aNAlTUHBWhrbiJpKdL4KIDs6hwh0QqLbnt8i7t02wq6qubGW0hYvdY3MQL2GfbNoIZUbYezp5eCyHm/8cFT/WTt1sGSg4hD8JbUn0GTMcrh4rrQLmcJbjStNUOyjqouASTK1A2QQxSS5p2Y7AC4yut3MIqyr7ByAX9/85HtHrdX3AgMBAAECggEAFWRBnzGCyeZhYB6OD+o30j1Dx001aNWiODNYs4t4VrSeoYMqBh3Gtm8x9HybNYwAJRLp4ulJl8i2NSjvK1IWqxgqIt87x74z3ed2tO46jknKGaOMCcfzN7t4b9BxLd83pekRyUewzbV7cVqTW5WTyAZ5EUp14Wtof7vtjsg8ndZp1C0LzJrsQ63LWJAWsfkiRwNwbjkIKTl12xwe3ctZD/PmxYVgWGog+32OiiiTuSf4O1ddp3y2kth66dSIO06VPCqgu8gLwG5epgHmy0Y1ugunpZINN2D7FCH7aaE+H+aQ4nltNIxpQV20grtQG546oDilfPCQLxeW1HUipq2wkQKBgQDyqo180/lJ4wSNFU/hNqLfs2629vU9MH9aSjG5nQpchkTgBxUhAE5RkKgQHLJHJTfPx7vkx2xkI3qddwsWzvt8lNs5NQNxh+LyXQEgy9FCfpopijy2epLpzd2WT+0Y9WK5oB7O32s2YW/6fm0ahu3EJnvBlp1M23FzuRfrV7gu5QKBgQCz98MyV0UAnP3x+Gq5/0siVGPInzYlfTfYcEI3qhlMfqPVkRqqHdGGsiQL70YJlTlZkLeh3r2UvoR956nV9lZgh37aWnaHw7FAYcA5z4FYEFdmpLK/8znaKn/fxypr9xkJtw5V1QgCeaSUCFbt0xp41LaAvwSDBfFqdOTzQMFHqwKBgEyZN4YypxsClPovwwI1K95vFkCc3baN63VFvEJ55r5kB7OrqKi9HvuyLMrBNCku/1oQEyhZJsbJSDgSTqbJeSrPFhANwuOAYEveva9rhsd1jRYVs6pqMJuqxwpeeloJgztS5saoUYBd62nnpGreMolbGG94KnkLP9mmkH1SOCpdAoGAbheD3ljKilx/cLVxvIRy1vZe8EyNGBPoxMuvhlPVFBloae5RLH3/PfHd4TsnUhdqNOM1op0axlJhxI+iMpR2NKjOrg6m8diBpwvlRrgsvM2KWe0ouAm3e0GCZkd1KQTI2UuVRmaCdtkpF7GeU/BPAlnFpy6zON+61k/Z+wDC++8CgYEA54xmJqIr19BpKkcHAxE2pzDrj6ssu2qObKLfsS27o4RevBnrhoY9kPwn8kUKpngoCTd7tM42y9fcpAdUDv+lENAcIF/kz4u+zkyRGR+SpirgAsCYzxZN3GfRNDHBaFEiTkyL6NFdPGV2GTPcd0b6JGf82Thb0JJCxB/J3hVnDIs="/>
+    <NotifyUrl value="http://218.17.158.45:15160/api/Asign/HandleASignCompleted"/>
+    <OpenApiUrl value="http://192.168.31.134:5015/mtp2-onlineopen"/>
+  </Asign>
 </Configuration>

+ 125 - 5
controllers/asign/auth.go

@@ -4,6 +4,7 @@ import (
 	"mtp2_if/global/app"
 	"mtp2_if/global/e"
 	"mtp2_if/logger"
+	"mtp2_if/models"
 	"net/http"
 
 	asignService "mtp2_if/services/asign"
@@ -13,13 +14,14 @@ import (
 
 // BankCard4 银行卡四要素认证
 // @Summary  银行卡四要素认证
-// @Produce  json
+// @Produce     json
 // @Security ApiKeyAuth
-// @accept   application/json
+// @accept      application/json
 // @Param    data body     asignService.BankCard4Req true "入参"
-// @Failure  500  {object} asignService.BankCard4Rsp
+// @Success  200  {object} asignService.BankCard4Rsp
+// @Failure     500  {object} app.Response
 // @Router   /Asign/BankCard4 [post]
-// @Tags     爱签
+// @Tags        爱签
 func BankCard4(c *gin.Context) {
 	appG := app.Gin{C: c}
 
@@ -34,6 +36,124 @@ func BankCard4(c *gin.Context) {
 	if rsp, err := asignService.BankCard4(req); err == nil {
 		appG.Response(http.StatusOK, e.SUCCESS, rsp)
 	} else {
-		appG.Response(http.StatusBadRequest, e.ERROR, nil)
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// CaptcaResend 重新发送认证验证码
+// @Summary     重新发送认证验证码
+// @Description 在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。
+// @Produce     json
+// @Security    ApiKeyAuth
+// @accept      application/json
+// @Param       data body     asignService.CaptchaResendReq true "入参"
+// @Success     200  {object} app.Response
+// @Failure     500  {object} app.Response
+// @Router      /Asign/CaptcaResend [post]
+// @Tags        爱签
+func CaptcaResend(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.CaptchaResendReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if err := asignService.CaptcaResend(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, "ok")
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// CaptchaVerify 认证验证码校验
+// @Summary     认证验证码校验
+// @Description 验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口
+// @Produce     json
+// @Security    ApiKeyAuth
+// @accept      application/json
+// @Param       data body     asignService.CaptchaVerifyReq true "入参"
+// @Success     200  {object} app.Response
+// @Failure     500  {object} app.Response
+// @Router      /Asign/CaptchaVerify [post]
+// @Tags        爱签
+func CaptchaVerify(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.CaptchaVerifyReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if err := asignService.CaptchaVerify(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, "ok")
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// CaptchaVerify 同步合同状态
+// @Summary     同步合同状态
+// @Description 此接口会调用爱签合同状态查询接口,并同步到交易系统用户电子签记录表记录中
+// @Produce  json
+// @accept   application/json
+// @Param       data body     asignService.SyncContractStatusReq true "入参"
+// @Success     200  {object} asignService.SyncContractStatusRsp
+// @Failure  500  {object} app.Response
+// @Router      /Asign/SyncContractStatus [post]
+// @Tags     爱签
+func SyncContractStatus(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.SyncContractStatusReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := asignService.SyncContractStatus(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// QueryUsereSignRecords 查询用户电子签记录表
+// @Summary  查询用户电子签记录表
+// @Produce  json
+// @Security ApiKeyAuth
+// @accept   application/json
+// @Param    userId           query    int true  "用户ID"
+// @Param    memberUserId     query    int true  "所属会员ID"
+// @Param    recordId         query    int false "记录ID"
+// @Param    templateConfigId query    int false "模板配置ID"
+// @Param    templatetype     query    int false "模板类型 - 1:实名认证 2:开户协议 3:日结算单 4:交易协议"
+// @Success  200              {array}  models.Useresignrecord
+// @Failure  500              {object} app.Response
+// @Router   /Asign/QueryUsereSignRecords [get]
+// @Tags     爱签
+func QueryUsereSignRecords(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.QueryUsereSignRecordsReq
+	if err := appG.C.ShouldBindQuery(&req); err != nil {
+		logger.GetLogger().Errorf("QueryUsereSignRecords failed: %s", err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := models.QueryUsereSignRecords(req.UserId, req.MemberUserId, req.RecordId, req.TemplateConfigId, req.Templatetype); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.Response(http.StatusBadRequest, e.ERROR_QUERY_FAIL, nil)
 	}
 }

+ 74 - 0
controllers/asign/contract.go

@@ -0,0 +1,74 @@
+package asign
+
+import (
+	"errors"
+	"mtp2_if/global/app"
+	"mtp2_if/global/e"
+	"mtp2_if/logger"
+	asignService "mtp2_if/services/asign"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+)
+
+// BankCard4 创建合同
+// @Summary  创建合同
+// @Produce  json
+// @Security ApiKeyAuth
+// @accept   application/json
+// @Param    data body     asignService.CreateContractReq true "入参"
+// @Success  200  {object} asignService.CreateContractRsp
+// @Failure  500  {object} app.Response
+// @Router   /Asign/CreateContract [post]
+// @Tags     爱签
+func CreateContract(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.CreateContractReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := asignService.CreateContract(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// 爱签合同签署完成后异步通知 POST
+func HandleASignCompleted(c *gin.Context) {
+	g := app.Gin{C: c}
+
+	action, ok := g.C.GetPostForm("action")
+	if !ok {
+		err := errors.New("获取action失败")
+		g.C.String(http.StatusBadRequest, "%s", err)
+		return
+	}
+	contractNo, ok := g.C.GetPostForm("contractNo")
+	if !ok {
+		err := errors.New("获取contractNo失败")
+		g.C.String(http.StatusBadRequest, "%s", err)
+		return
+	}
+	status, ok := g.C.GetPostForm("status")
+	if !ok {
+		err := errors.New("获取status失败")
+		g.C.String(http.StatusBadRequest, "%s", err)
+		return
+	}
+
+	if action == "signCompleted" {
+		if err := asignService.ASignCompleted(contractNo, status); err == nil {
+			g.C.String(http.StatusOK, "%s", "ok")
+		} else {
+			g.C.String(http.StatusBadRequest, "%s", err)
+		}
+	} else {
+		g.C.String(http.StatusOK, "%s", "ok")
+	}
+}

+ 125 - 0
controllers/asign/test.go

@@ -0,0 +1,125 @@
+package asign
+
+import (
+	"mtp2_if/global/app"
+	"mtp2_if/global/e"
+	"mtp2_if/logger"
+	asignService "mtp2_if/services/asign"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+)
+
+// BankCard4 银行卡四要素认证(测试)
+// @Summary  银行卡四要素认证(测试)
+// @Produce  json
+// @Security ApiKeyAuth
+// @accept   application/json
+// @Param    data body     asignService.APICompanyBankCard4Req true "入参"
+// @Success  200  {object} asignService.APIBankCard4Rsp
+// @Failure  500  {object} app.Response
+// @Router   /Asign/TestBankCard4 [post]
+// @Tags     爱签
+func TestBankCard4(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.APICompanyBankCard4Req
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := asignService.APICompanyBankCard4(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// CaptcaResend 重新发送认证验证码(测试)
+// @Summary     重新发送认证验证码(测试)
+// @Description 在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。
+// @Produce  json
+// @Security ApiKeyAuth
+// @accept   application/json
+// @Param       data body     asignService.APICaptchaResendReq true "入参"
+// @Success     200  {object} app.Response
+// @Failure  500  {object} app.Response
+// @Router      /Asign/TestCaptcaResend [post]
+// @Tags     爱签
+func TestCaptcaResend(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.APICaptchaResendReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := asignService.APICaptchaResend(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// CaptchaVerify 认证验证码校验(测试)
+// @Summary     认证验证码校验(测试)
+// @Description 验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口
+// @Produce     json
+// @Security    ApiKeyAuth
+// @accept      application/json
+// @Param       data body     asignService.APICaptchaVerifyReq true "入参"
+// @Success     200  {object} asignService.APICaptchaVerifyRsp
+// @Failure     500  {object} app.Response
+// @Router      /Asign/TestCaptchaVerify [post]
+// @Tags        爱签
+func TestCaptchaVerify(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.APICaptchaVerifyReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := asignService.APICaptchaVerify(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}
+
+// CaptchaVerify 添加企业用户(V2)(测试)
+// @Summary  添加企业用户(V2)(测试)
+// @Produce     json
+// @Security    ApiKeyAuth
+// @accept      application/json
+// @Param    data body     asignService.APIAddEnterpriseUserReq true "入参"
+// @Success  200  {object} asignService.APIAddUserRsp
+// @Failure     500  {object} app.Response
+// @Router   /Asign/TestAddEnterpriseUser [post]
+// @Tags        爱签
+func TestAddEnterpriseUser(c *gin.Context) {
+	appG := app.Gin{C: c}
+
+	// 获取请求参数
+	var req asignService.APIAddEnterpriseUserReq
+	if err := appG.C.ShouldBindJSON(&req); err != nil {
+		logger.GetLogger().Errorf(err.Error())
+		appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
+		return
+	}
+
+	if rsp, err := asignService.APIAddEnterpriseUser(req); err == nil {
+		appG.Response(http.StatusOK, e.SUCCESS, rsp)
+	} else {
+		appG.ResponseByMsg(http.StatusBadRequest, e.ERROR, err.Error(), nil)
+	}
+}

+ 2 - 1
controllers/ermcp/qryGoods.go

@@ -14,6 +14,7 @@ import (
 type GetErmcpGoodsReq struct {
 	LastUpdateTime string `form:"lastUpdateTime"`
 	USERID         int64  `form:"userid"`
+	LoginID        int64  `form:"loginid"` // 登录账号,传入后会进行有权限的市场过滤结果
 }
 
 // GetErmcpGoods 查询企业风管期货商品信息
@@ -38,7 +39,7 @@ func GetErmcpGoods(c *gin.Context) {
 	}
 
 	// 获取数据
-	goodses, err := models.GetErmcpGoodses(req.USERID, req.LastUpdateTime)
+	goodses, err := models.GetErmcpGoodses(req.USERID, req.LastUpdateTime, req.LoginID)
 	if err != nil {
 		// 查询失败
 		logger.GetLogger().Errorf("GetErmcpGoods failed: %s", err.Error())

+ 1 - 1
controllers/ermcp/qryUser.go

@@ -88,7 +88,7 @@ func GetErmcpRoleFuncMenuLists(c *gin.Context) {
 	}
 
 	// 查询成功返回
-	logger.GetLogger().Debugln("GetErmcpRolefuncMenu successed: %v", rst)
+	logger.GetLogger().Debugln("GetErmcpRolefuncMenu successed:", rst)
 	appG.Response(http.StatusOK, e.SUCCESS, rst)
 }
 

+ 1 - 1
controllers/market/market.go

@@ -220,7 +220,7 @@ func QueryGoodsesByLoginID(c *gin.Context) {
 	}
 
 	// 查询成功返回
-	logger.GetLogger().Debugln("QueryGoodsesByLoginID successed: %v", goodses)
+	logger.GetLogger().Debugln("QueryGoodsesByLoginID successed:", goodses)
 	appG.Response(http.StatusOK, e.SUCCESS, goodses)
 }
 

+ 2 - 2
controllers/quote/history.go

@@ -370,7 +370,7 @@ func QueryHistoryTikDatas(c *gin.Context) {
 	}
 
 	// 查询成功
-	logger.GetLogger().Debugln("QueryHistoryTikDatas successed, rows: %v", len(rst))
+	logger.GetLogger().Debugln("QueryHistoryTikDatas successed, rows:", len(rst))
 	appG.Response(http.StatusOK, e.SUCCESS, rst)
 }
 
@@ -738,7 +738,7 @@ func QueryTSData(c *gin.Context) {
 
 		diff := endTime.Sub(queryTSDataRsp.StartTime)
 		minute := int(diff.Minutes())
-		for i := 1; i <= minute; i++ {
+		for i := 0; i < minute; i++ {
 			st := int(queryTSDataRsp.StartTime.Unix()) + i*60
 			stt := time.Unix(int64(st), 0).Format("2006-01-02 15:04:05")
 			cycleDatas = append(cycleDatas, models.CycleData{

+ 707 - 1
docs/docs.go

@@ -46,10 +46,438 @@ const docTemplate = `{
                     }
                 ],
                 "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.BankCard4Rsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/CaptcaResend": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "重新发送认证验证码",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.CaptchaResendReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/CaptchaVerify": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "认证验证码校验",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.CaptchaVerifyReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/CreateContract": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "创建合同",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.CreateContractReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.CreateContractRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/QueryUsereSignRecords": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "查询用户电子签记录表",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "用户ID",
+                        "name": "userId",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "所属会员ID",
+                        "name": "memberUserId",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "记录ID",
+                        "name": "recordId",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "模板配置ID",
+                        "name": "templateConfigId",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "模板类型 - 1:实名认证 2:开户协议 3:日结算单 4:交易协议",
+                        "name": "templatetype",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/models.Useresignrecord"
+                            }
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/SyncContractStatus": {
+            "post": {
+                "description": "此接口会调用爱签合同状态查询接口,并同步到交易系统用户电子签记录表记录中",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "同步合同状态",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.SyncContractStatusReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.SyncContractStatusRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestAddEnterpriseUser": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "添加企业用户(V2)(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APIAddEnterpriseUserReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.APIAddUserRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestBankCard4": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "银行卡四要素认证(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICompanyBankCard4Req"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.APIBankCard4Rsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestCaptcaResend": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "重新发送认证验证码(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICaptchaResendReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    },
                     "500": {
                         "description": "Internal Server Error",
                         "schema": {
-                            "$ref": "#/definitions/asign.BankCard4Rsp"
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestCaptchaVerify": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "认证验证码校验(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICaptchaVerifyReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICaptchaVerifyRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
                         }
                     }
                 }
@@ -22768,6 +23196,182 @@ const docTemplate = `{
                 }
             }
         },
+        "asign.APIAddEnterpriseUserReq": {
+            "type": "object",
+            "required": [
+                "account"
+            ],
+            "properties": {
+                "account": {
+                    "description": "用户唯一识别码(可用证件号、手机号等具有唯一属性的标识作为参数传递)",
+                    "type": "string"
+                },
+                "companyName": {
+                    "description": "企业名称",
+                    "type": "string"
+                },
+                "contactIdCard": {
+                    "description": "联系人身份证号(与企业的法定代表人可以是同一个人)",
+                    "type": "string"
+                },
+                "contactName": {
+                    "description": "联系人姓名(与企业的法定代表人可以是同一个人)",
+                    "type": "string"
+                },
+                "creditCode": {
+                    "description": "企业证件号",
+                    "type": "string"
+                },
+                "creditType": {
+                    "description": "企业证件类型, 不传默认为1; 1:统一社会信用代码 2:表示其他证件类型",
+                    "type": "integer"
+                },
+                "idCard": {
+                    "description": "法人身份证、台胞证、港澳通行证等证件号",
+                    "type": "string"
+                },
+                "idCardType": {
+                    "description": "证件类型, 不传默认为1; 1:居民身份证 2:台湾居民来往大陆通行证 3:港澳居民来往内地通行证等...",
+                    "type": "integer"
+                },
+                "isNotice": {
+                    "description": "用户发起合同或需要签署时是否进行短信通知: 0-否(默认), 1-是",
+                    "type": "integer"
+                },
+                "isSignPwdNotice": {
+                    "description": "是否将签约密码以短信形式通知用户: 0-不通知(默认), 1-通知",
+                    "type": "integer"
+                },
+                "mobile": {
+                    "description": "签约手机,该手机号将用于企业用户合同签署时短信验证,请确保真实有效",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "企业法人姓名",
+                    "type": "string"
+                },
+                "serialNo": {
+                    "description": "实名认证流水号(若您希望不传此值,由您自行完成认证。请联系商务人员开通权限)",
+                    "type": "string"
+                },
+                "signPwd": {
+                    "description": "签约密码明文,如果为空我方将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APIAddUserRsp": {
+            "type": "object",
+            "required": [
+                "sealNo"
+            ],
+            "properties": {
+                "sealNo": {
+                    "description": "生成默认印章编号",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APIBankCard4Rsp": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "description": "认证结果 0.暂无结果/认证中 1.成功 2.失败",
+                    "type": "integer"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "type": {
+                    "description": "认证类型",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICaptchaResendReq": {
+            "type": "object",
+            "required": [
+                "serialNo"
+            ],
+            "properties": {
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICaptchaVerifyReq": {
+            "type": "object",
+            "required": [
+                "captcha",
+                "serialNo"
+            ],
+            "properties": {
+                "captcha": {
+                    "description": "短信验证码",
+                    "type": "string"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICaptchaVerifyRsp": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "description": "认证结果 0.暂无结果/认证中 1.成功 2.失败",
+                    "type": "integer"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "type": {
+                    "description": "认证类型",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICompanyBankCard4Req": {
+            "type": "object",
+            "required": [
+                "bankCard",
+                "companyName",
+                "creditCode",
+                "idCardNo",
+                "mobile",
+                "realName"
+            ],
+            "properties": {
+                "bankCard": {
+                    "description": "法人银行卡号(仅限印有“银联”字样的银行卡)",
+                    "type": "string"
+                },
+                "companyName": {
+                    "description": "企业名称",
+                    "type": "string"
+                },
+                "creditCode": {
+                    "description": "社会统一信用代码",
+                    "type": "string"
+                },
+                "idCardNo": {
+                    "description": "法人身份证号",
+                    "type": "string"
+                },
+                "mobile": {
+                    "description": "法人手机号(限中国大陆11位手机号)",
+                    "type": "string"
+                },
+                "realName": {
+                    "description": "法人姓名",
+                    "type": "string"
+                }
+            }
+        },
         "asign.BankCard4Req": {
             "type": "object",
             "required": [
@@ -22802,6 +23406,46 @@ const docTemplate = `{
                 }
             }
         },
+        "asign.CaptchaResendReq": {
+            "type": "object",
+            "properties": {
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "timeStamp": {
+                    "description": "时间戳,可不传(S1016)",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.CaptchaVerifyReq": {
+            "type": "object",
+            "required": [
+                "captcha",
+                "serialNo",
+                "type",
+                "userId"
+            ],
+            "properties": {
+                "captcha": {
+                    "description": "短信验证码",
+                    "type": "string"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "type": {
+                    "description": "实体类型 1:个人 2:企业",
+                    "type": "integer"
+                },
+                "userId": {
+                    "description": "用户ID",
+                    "type": "integer"
+                }
+            }
+        },
         "asign.CompanyBankCard4": {
             "type": "object",
             "properties": {
@@ -22821,6 +23465,10 @@ const docTemplate = `{
                     "description": "法人身份证号",
                     "type": "string"
                 },
+                "idCardPhoto": {
+                    "description": "营业执照",
+                    "type": "string"
+                },
                 "mobile": {
                     "description": "法人手机号(限中国大陆11位手机号)",
                     "type": "string"
@@ -22831,6 +23479,27 @@ const docTemplate = `{
                 }
             }
         },
+        "asign.CreateContractReq": {
+            "type": "object",
+            "required": [
+                "recordId"
+            ],
+            "properties": {
+                "recordId": {
+                    "description": "用户电子签记录表记录ID",
+                    "type": "integer"
+                }
+            }
+        },
+        "asign.CreateContractRsp": {
+            "type": "object",
+            "properties": {
+                "signUrl": {
+                    "description": "合同签署链接",
+                    "type": "string"
+                }
+            }
+        },
         "asign.PersonBankCard4": {
             "type": "object",
             "properties": {
@@ -22842,6 +23511,14 @@ const docTemplate = `{
                     "description": "身份证号",
                     "type": "string"
                 },
+                "idCardPhoto": {
+                    "description": "证件照正面",
+                    "type": "string"
+                },
+                "idCardPhotoBackURL": {
+                    "description": "证件照背面",
+                    "type": "string"
+                },
                 "mobile": {
                     "description": "手机号码(限中国大陆11位手机号)",
                     "type": "string"
@@ -22852,6 +23529,35 @@ const docTemplate = `{
                 }
             }
         },
+        "asign.SyncContractStatusReq": {
+            "type": "object",
+            "required": [
+                "recordId"
+            ],
+            "properties": {
+                "recordId": {
+                    "description": "用户电子签记录表记录ID",
+                    "type": "integer"
+                }
+            }
+        },
+        "asign.SyncContractStatusRsp": {
+            "type": "object",
+            "properties": {
+                "contractName": {
+                    "description": "合同名称",
+                    "type": "string"
+                },
+                "contractNo": {
+                    "description": "合同唯一编号",
+                    "type": "string"
+                },
+                "status": {
+                    "description": "爱签合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常",
+                    "type": "integer"
+                }
+            }
+        },
         "common.ClientMenu": {
             "type": "object",
             "properties": {

+ 707 - 1
docs/swagger.json

@@ -37,10 +37,438 @@
                     }
                 ],
                 "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.BankCard4Rsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/CaptcaResend": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "重新发送认证验证码",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.CaptchaResendReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/CaptchaVerify": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "认证验证码校验",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.CaptchaVerifyReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/CreateContract": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "创建合同",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.CreateContractReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.CreateContractRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/QueryUsereSignRecords": {
+            "get": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "查询用户电子签记录表",
+                "parameters": [
+                    {
+                        "type": "integer",
+                        "description": "用户ID",
+                        "name": "userId",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "所属会员ID",
+                        "name": "memberUserId",
+                        "in": "query",
+                        "required": true
+                    },
+                    {
+                        "type": "integer",
+                        "description": "记录ID",
+                        "name": "recordId",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "模板配置ID",
+                        "name": "templateConfigId",
+                        "in": "query"
+                    },
+                    {
+                        "type": "integer",
+                        "description": "模板类型 - 1:实名认证 2:开户协议 3:日结算单 4:交易协议",
+                        "name": "templatetype",
+                        "in": "query"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/models.Useresignrecord"
+                            }
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/SyncContractStatus": {
+            "post": {
+                "description": "此接口会调用爱签合同状态查询接口,并同步到交易系统用户电子签记录表记录中",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "同步合同状态",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.SyncContractStatusReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.SyncContractStatusRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestAddEnterpriseUser": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "添加企业用户(V2)(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APIAddEnterpriseUserReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.APIAddUserRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestBankCard4": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "银行卡四要素认证(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICompanyBankCard4Req"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.APIBankCard4Rsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestCaptcaResend": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "重新发送认证验证码(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICaptchaResendReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    },
                     "500": {
                         "description": "Internal Server Error",
                         "schema": {
-                            "$ref": "#/definitions/asign.BankCard4Rsp"
+                            "$ref": "#/definitions/app.Response"
+                        }
+                    }
+                }
+            }
+        },
+        "/Asign/TestCaptchaVerify": {
+            "post": {
+                "security": [
+                    {
+                        "ApiKeyAuth": []
+                    }
+                ],
+                "description": "验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "爱签"
+                ],
+                "summary": "认证验证码校验(测试)",
+                "parameters": [
+                    {
+                        "description": "入参",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICaptchaVerifyReq"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/asign.APICaptchaVerifyRsp"
+                        }
+                    },
+                    "500": {
+                        "description": "Internal Server Error",
+                        "schema": {
+                            "$ref": "#/definitions/app.Response"
                         }
                     }
                 }
@@ -22759,6 +23187,182 @@
                 }
             }
         },
+        "asign.APIAddEnterpriseUserReq": {
+            "type": "object",
+            "required": [
+                "account"
+            ],
+            "properties": {
+                "account": {
+                    "description": "用户唯一识别码(可用证件号、手机号等具有唯一属性的标识作为参数传递)",
+                    "type": "string"
+                },
+                "companyName": {
+                    "description": "企业名称",
+                    "type": "string"
+                },
+                "contactIdCard": {
+                    "description": "联系人身份证号(与企业的法定代表人可以是同一个人)",
+                    "type": "string"
+                },
+                "contactName": {
+                    "description": "联系人姓名(与企业的法定代表人可以是同一个人)",
+                    "type": "string"
+                },
+                "creditCode": {
+                    "description": "企业证件号",
+                    "type": "string"
+                },
+                "creditType": {
+                    "description": "企业证件类型, 不传默认为1; 1:统一社会信用代码 2:表示其他证件类型",
+                    "type": "integer"
+                },
+                "idCard": {
+                    "description": "法人身份证、台胞证、港澳通行证等证件号",
+                    "type": "string"
+                },
+                "idCardType": {
+                    "description": "证件类型, 不传默认为1; 1:居民身份证 2:台湾居民来往大陆通行证 3:港澳居民来往内地通行证等...",
+                    "type": "integer"
+                },
+                "isNotice": {
+                    "description": "用户发起合同或需要签署时是否进行短信通知: 0-否(默认), 1-是",
+                    "type": "integer"
+                },
+                "isSignPwdNotice": {
+                    "description": "是否将签约密码以短信形式通知用户: 0-不通知(默认), 1-通知",
+                    "type": "integer"
+                },
+                "mobile": {
+                    "description": "签约手机,该手机号将用于企业用户合同签署时短信验证,请确保真实有效",
+                    "type": "string"
+                },
+                "name": {
+                    "description": "企业法人姓名",
+                    "type": "string"
+                },
+                "serialNo": {
+                    "description": "实名认证流水号(若您希望不传此值,由您自行完成认证。请联系商务人员开通权限)",
+                    "type": "string"
+                },
+                "signPwd": {
+                    "description": "签约密码明文,如果为空我方将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APIAddUserRsp": {
+            "type": "object",
+            "required": [
+                "sealNo"
+            ],
+            "properties": {
+                "sealNo": {
+                    "description": "生成默认印章编号",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APIBankCard4Rsp": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "description": "认证结果 0.暂无结果/认证中 1.成功 2.失败",
+                    "type": "integer"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "type": {
+                    "description": "认证类型",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICaptchaResendReq": {
+            "type": "object",
+            "required": [
+                "serialNo"
+            ],
+            "properties": {
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICaptchaVerifyReq": {
+            "type": "object",
+            "required": [
+                "captcha",
+                "serialNo"
+            ],
+            "properties": {
+                "captcha": {
+                    "description": "短信验证码",
+                    "type": "string"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICaptchaVerifyRsp": {
+            "type": "object",
+            "properties": {
+                "result": {
+                    "description": "认证结果 0.暂无结果/认证中 1.成功 2.失败",
+                    "type": "integer"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "type": {
+                    "description": "认证类型",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.APICompanyBankCard4Req": {
+            "type": "object",
+            "required": [
+                "bankCard",
+                "companyName",
+                "creditCode",
+                "idCardNo",
+                "mobile",
+                "realName"
+            ],
+            "properties": {
+                "bankCard": {
+                    "description": "法人银行卡号(仅限印有“银联”字样的银行卡)",
+                    "type": "string"
+                },
+                "companyName": {
+                    "description": "企业名称",
+                    "type": "string"
+                },
+                "creditCode": {
+                    "description": "社会统一信用代码",
+                    "type": "string"
+                },
+                "idCardNo": {
+                    "description": "法人身份证号",
+                    "type": "string"
+                },
+                "mobile": {
+                    "description": "法人手机号(限中国大陆11位手机号)",
+                    "type": "string"
+                },
+                "realName": {
+                    "description": "法人姓名",
+                    "type": "string"
+                }
+            }
+        },
         "asign.BankCard4Req": {
             "type": "object",
             "required": [
@@ -22793,6 +23397,46 @@
                 }
             }
         },
+        "asign.CaptchaResendReq": {
+            "type": "object",
+            "properties": {
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "timeStamp": {
+                    "description": "时间戳,可不传(S1016)",
+                    "type": "string"
+                }
+            }
+        },
+        "asign.CaptchaVerifyReq": {
+            "type": "object",
+            "required": [
+                "captcha",
+                "serialNo",
+                "type",
+                "userId"
+            ],
+            "properties": {
+                "captcha": {
+                    "description": "短信验证码",
+                    "type": "string"
+                },
+                "serialNo": {
+                    "description": "认证流水号",
+                    "type": "string"
+                },
+                "type": {
+                    "description": "实体类型 1:个人 2:企业",
+                    "type": "integer"
+                },
+                "userId": {
+                    "description": "用户ID",
+                    "type": "integer"
+                }
+            }
+        },
         "asign.CompanyBankCard4": {
             "type": "object",
             "properties": {
@@ -22812,6 +23456,10 @@
                     "description": "法人身份证号",
                     "type": "string"
                 },
+                "idCardPhoto": {
+                    "description": "营业执照",
+                    "type": "string"
+                },
                 "mobile": {
                     "description": "法人手机号(限中国大陆11位手机号)",
                     "type": "string"
@@ -22822,6 +23470,27 @@
                 }
             }
         },
+        "asign.CreateContractReq": {
+            "type": "object",
+            "required": [
+                "recordId"
+            ],
+            "properties": {
+                "recordId": {
+                    "description": "用户电子签记录表记录ID",
+                    "type": "integer"
+                }
+            }
+        },
+        "asign.CreateContractRsp": {
+            "type": "object",
+            "properties": {
+                "signUrl": {
+                    "description": "合同签署链接",
+                    "type": "string"
+                }
+            }
+        },
         "asign.PersonBankCard4": {
             "type": "object",
             "properties": {
@@ -22833,6 +23502,14 @@
                     "description": "身份证号",
                     "type": "string"
                 },
+                "idCardPhoto": {
+                    "description": "证件照正面",
+                    "type": "string"
+                },
+                "idCardPhotoBackURL": {
+                    "description": "证件照背面",
+                    "type": "string"
+                },
                 "mobile": {
                     "description": "手机号码(限中国大陆11位手机号)",
                     "type": "string"
@@ -22843,6 +23520,35 @@
                 }
             }
         },
+        "asign.SyncContractStatusReq": {
+            "type": "object",
+            "required": [
+                "recordId"
+            ],
+            "properties": {
+                "recordId": {
+                    "description": "用户电子签记录表记录ID",
+                    "type": "integer"
+                }
+            }
+        },
+        "asign.SyncContractStatusRsp": {
+            "type": "object",
+            "properties": {
+                "contractName": {
+                    "description": "合同名称",
+                    "type": "string"
+                },
+                "contractNo": {
+                    "description": "合同唯一编号",
+                    "type": "string"
+                },
+                "status": {
+                    "description": "爱签合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常",
+                    "type": "integer"
+                }
+            }
+        },
         "common.ClientMenu": {
             "type": "object",
             "properties": {

+ 468 - 1
docs/swagger.yaml

@@ -16,6 +16,133 @@ definitions:
         description: 总条数
         type: integer
     type: object
+  asign.APIAddEnterpriseUserReq:
+    properties:
+      account:
+        description: 用户唯一识别码(可用证件号、手机号等具有唯一属性的标识作为参数传递)
+        type: string
+      companyName:
+        description: 企业名称
+        type: string
+      contactIdCard:
+        description: 联系人身份证号(与企业的法定代表人可以是同一个人)
+        type: string
+      contactName:
+        description: 联系人姓名(与企业的法定代表人可以是同一个人)
+        type: string
+      creditCode:
+        description: 企业证件号
+        type: string
+      creditType:
+        description: 企业证件类型, 不传默认为1; 1:统一社会信用代码 2:表示其他证件类型
+        type: integer
+      idCard:
+        description: 法人身份证、台胞证、港澳通行证等证件号
+        type: string
+      idCardType:
+        description: 证件类型, 不传默认为1; 1:居民身份证 2:台湾居民来往大陆通行证 3:港澳居民来往内地通行证等...
+        type: integer
+      isNotice:
+        description: '用户发起合同或需要签署时是否进行短信通知: 0-否(默认), 1-是'
+        type: integer
+      isSignPwdNotice:
+        description: '是否将签约密码以短信形式通知用户: 0-不通知(默认), 1-通知'
+        type: integer
+      mobile:
+        description: 签约手机,该手机号将用于企业用户合同签署时短信验证,请确保真实有效
+        type: string
+      name:
+        description: 企业法人姓名
+        type: string
+      serialNo:
+        description: 实名认证流水号(若您希望不传此值,由您自行完成认证。请联系商务人员开通权限)
+        type: string
+      signPwd:
+        description: 签约密码明文,如果为空我方将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)
+        type: string
+    required:
+    - account
+    type: object
+  asign.APIAddUserRsp:
+    properties:
+      sealNo:
+        description: 生成默认印章编号
+        type: string
+    required:
+    - sealNo
+    type: object
+  asign.APIBankCard4Rsp:
+    properties:
+      result:
+        description: 认证结果 0.暂无结果/认证中 1.成功 2.失败
+        type: integer
+      serialNo:
+        description: 认证流水号
+        type: string
+      type:
+        description: 认证类型
+        type: string
+    type: object
+  asign.APICaptchaResendReq:
+    properties:
+      serialNo:
+        description: 认证流水号
+        type: string
+    required:
+    - serialNo
+    type: object
+  asign.APICaptchaVerifyReq:
+    properties:
+      captcha:
+        description: 短信验证码
+        type: string
+      serialNo:
+        description: 认证流水号
+        type: string
+    required:
+    - captcha
+    - serialNo
+    type: object
+  asign.APICaptchaVerifyRsp:
+    properties:
+      result:
+        description: 认证结果 0.暂无结果/认证中 1.成功 2.失败
+        type: integer
+      serialNo:
+        description: 认证流水号
+        type: string
+      type:
+        description: 认证类型
+        type: string
+    type: object
+  asign.APICompanyBankCard4Req:
+    properties:
+      bankCard:
+        description: 法人银行卡号(仅限印有“银联”字样的银行卡)
+        type: string
+      companyName:
+        description: 企业名称
+        type: string
+      creditCode:
+        description: 社会统一信用代码
+        type: string
+      idCardNo:
+        description: 法人身份证号
+        type: string
+      mobile:
+        description: 法人手机号(限中国大陆11位手机号)
+        type: string
+      realName:
+        description: 法人姓名
+        type: string
+    required:
+    - bankCard
+    - companyName
+    - creditCode
+    - idCardNo
+    - mobile
+    - realName
+    type: object
   asign.BankCard4Req:
     properties:
       company:
@@ -40,6 +167,35 @@ definitions:
         description: 认证流水号
         type: string
     type: object
+  asign.CaptchaResendReq:
+    properties:
+      serialNo:
+        description: 认证流水号
+        type: string
+      timeStamp:
+        description: 时间戳,可不传(S1016)
+        type: string
+    type: object
+  asign.CaptchaVerifyReq:
+    properties:
+      captcha:
+        description: 短信验证码
+        type: string
+      serialNo:
+        description: 认证流水号
+        type: string
+      type:
+        description: 实体类型 1:个人 2:企业
+        type: integer
+      userId:
+        description: 用户ID
+        type: integer
+    required:
+    - captcha
+    - serialNo
+    - type
+    - userId
+    type: object
   asign.CompanyBankCard4:
     properties:
       bankCard:
@@ -54,6 +210,9 @@ definitions:
       idCardNo:
         description: 法人身份证号
         type: string
+      idCardPhoto:
+        description: 营业执照
+        type: string
       mobile:
         description: 法人手机号(限中国大陆11位手机号)
         type: string
@@ -61,6 +220,20 @@ definitions:
         description: 法人姓名
         type: string
     type: object
+  asign.CreateContractReq:
+    properties:
+      recordId:
+        description: 用户电子签记录表记录ID
+        type: integer
+    required:
+    - recordId
+    type: object
+  asign.CreateContractRsp:
+    properties:
+      signUrl:
+        description: 合同签署链接
+        type: string
+    type: object
   asign.PersonBankCard4:
     properties:
       bankCard:
@@ -69,6 +242,12 @@ definitions:
       idCardNo:
         description: 身份证号
         type: string
+      idCardPhoto:
+        description: 证件照正面
+        type: string
+      idCardPhotoBackURL:
+        description: 证件照背面
+        type: string
       mobile:
         description: 手机号码(限中国大陆11位手机号)
         type: string
@@ -76,6 +255,26 @@ definitions:
         description: 真实姓名
         type: string
     type: object
+  asign.SyncContractStatusReq:
+    properties:
+      recordId:
+        description: 用户电子签记录表记录ID
+        type: integer
+    required:
+    - recordId
+    type: object
+  asign.SyncContractStatusRsp:
+    properties:
+      contractName:
+        description: 合同名称
+        type: string
+      contractNo:
+        description: 合同唯一编号
+        type: string
+      status:
+        description: 爱签合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常
+        type: integer
+    type: object
   common.ClientMenu:
     properties:
       children:
@@ -30776,15 +30975,283 @@ paths:
       produces:
       - application/json
       responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/asign.BankCard4Rsp'
         "500":
           description: Internal Server Error
           schema:
-            $ref: '#/definitions/asign.BankCard4Rsp'
+            $ref: '#/definitions/app.Response'
       security:
       - ApiKeyAuth: []
       summary: 银行卡四要素认证
       tags:
       - 爱签
+  /Asign/CaptcaResend:
+    post:
+      consumes:
+      - application/json
+      description: 在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.CaptchaResendReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/app.Response'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 重新发送认证验证码
+      tags:
+      - 爱签
+  /Asign/CaptchaVerify:
+    post:
+      consumes:
+      - application/json
+      description: 验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.CaptchaVerifyReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/app.Response'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 认证验证码校验
+      tags:
+      - 爱签
+  /Asign/CreateContract:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.CreateContractReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/asign.CreateContractRsp'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 创建合同
+      tags:
+      - 爱签
+  /Asign/QueryUsereSignRecords:
+    get:
+      consumes:
+      - application/json
+      parameters:
+      - description: 用户ID
+        in: query
+        name: userId
+        required: true
+        type: integer
+      - description: 所属会员ID
+        in: query
+        name: memberUserId
+        required: true
+        type: integer
+      - description: 记录ID
+        in: query
+        name: recordId
+        type: integer
+      - description: 模板配置ID
+        in: query
+        name: templateConfigId
+        type: integer
+      - description: 模板类型 - 1:实名认证 2:开户协议 3:日结算单 4:交易协议
+        in: query
+        name: templatetype
+        type: integer
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            items:
+              $ref: '#/definitions/models.Useresignrecord'
+            type: array
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 查询用户电子签记录表
+      tags:
+      - 爱签
+  /Asign/SyncContractStatus:
+    post:
+      consumes:
+      - application/json
+      description: 此接口会调用爱签合同状态查询接口,并同步到交易系统用户电子签记录表记录中
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.SyncContractStatusReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/asign.SyncContractStatusRsp'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      summary: 同步合同状态
+      tags:
+      - 爱签
+  /Asign/TestAddEnterpriseUser:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.APIAddEnterpriseUserReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/asign.APIAddUserRsp'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 添加企业用户(V2)(测试)
+      tags:
+      - 爱签
+  /Asign/TestBankCard4:
+    post:
+      consumes:
+      - application/json
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.APICompanyBankCard4Req'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/asign.APIBankCard4Rsp'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 银行卡四要素认证(测试)
+      tags:
+      - 爱签
+  /Asign/TestCaptcaResend:
+    post:
+      consumes:
+      - application/json
+      description: 在实名认证的过程中,因用户手机原因未收到短信验证码或原验证码超过15分钟有效期而过期时,可以调用此接口重新发送短信验证码。若1分钟内多次调用此接口,则仅会发送一次短信验证码,15分钟内重新发送短信验证码不会变化。
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.APICaptchaResendReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/app.Response'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 重新发送认证验证码(测试)
+      tags:
+      - 爱签
+  /Asign/TestCaptchaVerify:
+    post:
+      consumes:
+      - application/json
+      description: 验证码认证成功后会调用爱签添加用户接口,同时调用交易系统JAVA实名认证接口
+      parameters:
+      - description: 入参
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/asign.APICaptchaVerifyReq'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/asign.APICaptchaVerifyRsp'
+        "500":
+          description: Internal Server Error
+          schema:
+            $ref: '#/definitions/app.Response'
+      security:
+      - ApiKeyAuth: []
+      summary: 认证验证码校验(测试)
+      tags:
+      - 爱签
   /Bank/QueryBankBranChnumInfo:
     get:
       parameters:

+ 1 - 0
go.mod

@@ -68,6 +68,7 @@ require (
 	github.com/KyleBanks/depth v1.2.1 // indirect
 	github.com/PuerkitoBio/purell v1.1.1 // indirect
 	github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
+	github.com/bwmarrin/snowflake v0.3.0 // indirect
 	github.com/bytedance/sonic v1.8.0 // indirect
 	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
 	github.com/fsnotify/fsnotify v1.4.7 // indirect

+ 2 - 0
go.sum

@@ -22,6 +22,8 @@ github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
 github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
 github.com/bndr/gotabulate v1.1.2 h1:yC9izuZEphojb9r+KYL4W9IJKO/ceIO8HDwxMA24U4c=
 github.com/bndr/gotabulate v1.1.2/go.mod h1:0+8yUgaPTtLRTjf49E8oju7ojpU11YmXyvq1LbPAb3U=
+github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
+github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
 github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
 github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=

+ 3 - 0
main.go

@@ -139,6 +139,9 @@ func main() {
 		timeout = 60 * time.Second
 	}
 
+	// 初始化雪化
+	utils.InitSnowflake(time.Now(), 1)
+
 	// 声明web服务
 	webser := &http.Server{
 		Handler:      r,

+ 20 - 2
models/ermcpGoods.go

@@ -89,7 +89,7 @@ type ErmcpGoods struct {
 }
 
 // GetErmcpGoodses 企业风管专用获取商品信息的方法
-func GetErmcpGoodses(userid int64, lastUpdateTime string) ([]ErmcpGoods, error) {
+func GetErmcpGoodses(userid int64, lastUpdateTime string, loginID int64) ([]ErmcpGoods, error) {
 	engine := db.GetEngine()
 
 	// 对比数据库与终端的更新时间戳
@@ -101,6 +101,20 @@ func GetErmcpGoodses(userid int64, lastUpdateTime string) ([]ErmcpGoods, error)
 		}
 	}
 
+	// 获取此账号相关有权限的市场
+	ids := make([]int, 0)
+	if loginID != 0 {
+		markets, err := GetMarketsByLoginID(int(loginID))
+		if err != nil {
+			return make([]ErmcpGoods, 0), err
+		}
+
+		// 构建市场ID列表
+		for _, market := range markets {
+			ids = append(ids, int(market.Marketid))
+		}
+	}
+
 	goodses := make([]ErmcpGoods, 0)
 	session := engine.Table("GOODS G").
 		Select(`
@@ -116,7 +130,11 @@ func GetErmcpGoodses(userid int64, lastUpdateTime string) ([]ErmcpGoods, error)
 		Join("LEFT", "MARKET M", "M.MARKETID = G.MARKETID").
 		Join("LEFT", "GOODSMARGINCONFIG GM", "GM.GOODSID = G.GOODSID AND GM.ISDEFAULT = 1").
 		Join("LEFT", "GOODSEX EX", "EX.GOODSID = G.GOODSID").
-		Where("G.GOODSSTATUS in (3, 7)").OrderBy("G.GOODSCODE")
+		Where("G.GOODSSTATUS in (3, 7)")
+	if loginID != 0 {
+		session = session.In("G.MARKETID", ids)
+	}
+	session = session.OrderBy("G.GOODSCODE")
 
 	if err := session.Find(&goodses); err != nil {
 		return nil, err

+ 16 - 0
models/ori.go

@@ -1010,3 +1010,19 @@ type OriUserinfo struct {
 func (r *OriUserinfo) TableName() string {
 	return "USERINFO"
 }
+
+// Esigntemplatefield 电子签模板字段配置表 - 脚本初始化
+type Esigntemplatefield struct {
+	TEMPLATEFIELDID  int64     `json:"templatefieldid" xorm:"TEMPLATEFIELDID"`   // 模板字段ID
+	TEMPLATECONFIGID int64     `json:"templateconfigid" xorm:"TEMPLATECONFIGID"` // 模板配置ID
+	FIELDNAME        string    `json:"fieldname" xorm:"FIELDNAME"`               // 字段名称
+	FIELDKEY         string    `json:"fieldkey" xorm:"FIELDKEY"`                 // 字段Key
+	FIELDTYPE        int32     `json:"fieldtype" xorm:"FIELDTYPE"`               // 字段类型 - 1:文本 2:日期
+	REMARK           string    `json:"remark" xorm:"REMARK"`                     // 字段备注
+	CREATETIME       time.Time `json:"createtime" xorm:"CREATETIME"`             // 创建时间
+}
+
+// TableName is ESIGNTEMPLATEFIELD
+func (r *Esigntemplatefield) TableName() string {
+	return "ESIGNTEMPLATEFIELD"
+}

+ 20 - 0
routers/router.go

@@ -2,6 +2,7 @@ package routers
 
 import (
 	"mtp2_if/config"
+	"mtp2_if/controllers/asign"
 	"mtp2_if/controllers/bank"
 	"mtp2_if/controllers/cfg"
 	"mtp2_if/controllers/common"
@@ -842,6 +843,25 @@ func InitRouter() *gin.Engine {
 		tencentR.Use(token.Auth()).POST("InitMdUserSwapProtocol", tencent.InitMdUserSwapProtocol)
 	}
 
+	// ************************* 爱签 *************************
+	asignR := apiR.Group("Asign")
+	asignR.Use()
+	{
+		asignR.Use().POST("SyncContractStatus", asign.SyncContractStatus)
+		asignR.Use().POST("HandleASignCompleted", asign.HandleASignCompleted)
+
+		asignR.Use(token.Auth()).POST("BankCard4", asign.BankCard4)
+		asignR.Use(token.Auth()).POST("CaptcaResend", asign.CaptcaResend)
+		asignR.Use(token.Auth()).POST("CaptchaVerify", asign.CaptchaVerify)
+		asignR.Use(token.Auth()).GET("QueryUsereSignRecords", asign.QueryUsereSignRecords)
+		asignR.Use(token.Auth()).POST("CreateContract", asign.CreateContract)
+
+		// asignR.Use(token.Auth()).POST("TestBankCard4", asign.TestBankCard4)
+		// asignR.Use(token.Auth()).POST("TestCaptcaResend", asign.TestCaptcaResend)
+		// asignR.Use(token.Auth()).POST("TestCaptchaVerify", asign.TestCaptchaVerify)
+		// asignR.Use(token.Auth()).POST("TestAddEnterpriseUser", asign.TestAddEnterpriseUser)
+	}
+
 	return r
 }
 

+ 143 - 2
services/asign/api.go

@@ -101,7 +101,7 @@ func APICaptchaVerify(req APICaptchaVerifyReq) (rsp *APIRsp[APICaptchaVerifyRsp]
 }
 
 // APIGetUser 查询用户信息
-func APIGetUser(req APIGetUserReq) (rsp *APIRsp[APIGetUserRsp], err error) {
+func APIGetUser(req APIGetUserReq) (rsp *APIRsp[[]APIGetUserRsp], err error) {
 	apiUrl := config.SerCfg.AsignCfg.Url + "/user/getUser"
 
 	reqMap := structs.Map(req)
@@ -117,7 +117,148 @@ func APIGetUser(req APIGetUserReq) (rsp *APIRsp[APIGetUserRsp], err error) {
 		return
 	}
 	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
-	rsp = new(APIRsp[APIGetUserRsp])
+	rsp = new(APIRsp[[]APIGetUserRsp])
+	err = json.Unmarshal(rspBody, rsp)
+
+	return
+}
+
+// APIAddPersonalUser 添加个人用户(V2)
+func APIAddPersonalUser(req APIAddPersonalUserReq) (rsp *APIRsp[APIAddUserRsp], err error) {
+	apiUrl := config.SerCfg.AsignCfg.Url + "/v2/user/addPersonalUser"
+
+	reqMap := structs.Map(req)
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqMap)
+	rspBody, err := HttpPost(apiUrl, reqMap)
+	if err != nil {
+		logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
+		return
+	}
+	rspStr := string(rspBody)
+	if len(rspStr) == 0 {
+		logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
+		return
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
+	rsp = new(APIRsp[APIAddUserRsp])
+	err = json.Unmarshal(rspBody, rsp)
+
+	return
+}
+
+// APIAddEnterpriseUser 添加企业用户(V2)
+func APIAddEnterpriseUser(req APIAddEnterpriseUserReq) (rsp *APIRsp[APIAddUserRsp], err error) {
+	apiUrl := config.SerCfg.AsignCfg.Url + "/v2/user/addEnterpriseUser"
+
+	reqMap := structs.Map(req)
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqMap)
+	rspBody, err := HttpPost(apiUrl, reqMap)
+	if err != nil {
+		logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
+		return
+	}
+	rspStr := string(rspBody)
+	if len(rspStr) == 0 {
+		logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
+		return
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
+	rsp = new(APIRsp[APIAddUserRsp])
+	err = json.Unmarshal(rspBody, rsp)
+
+	return
+}
+
+// APITemplateList 查询模板列表
+func APITemplateList(req APITemplateListReq) (rsp *APIRsp[APITemplateListRsp], err error) {
+	apiUrl := config.SerCfg.AsignCfg.Url + "/template/list"
+
+	reqMap := structs.Map(req)
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqMap)
+	rspBody, err := HttpPost(apiUrl, reqMap)
+	if err != nil {
+		logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
+		return
+	}
+	rspStr := string(rspBody)
+	if len(rspStr) == 0 {
+		logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
+		return
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
+	rsp = new(APIRsp[APITemplateListRsp])
+	err = json.Unmarshal(rspBody, rsp)
+
+	return
+}
+
+// APICreateContract 上传待签署文件
+func APICreateContract(req APICreateContractReq) (rsp *APIRsp[APICreateContractRsp], err error) {
+	apiUrl := config.SerCfg.AsignCfg.Url + "/contract/createContract"
+
+	reqMap := structs.Map(req)
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqMap)
+	rspBody, err := HttpPost(apiUrl, reqMap)
+	if err != nil {
+		logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
+		return
+	}
+	rspStr := string(rspBody)
+	if len(rspStr) == 0 {
+		logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
+		return
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
+	rsp = new(APIRsp[APICreateContractRsp])
+	err = json.Unmarshal(rspBody, rsp)
+
+	return
+}
+
+// APIAddSigner 添加签署方
+func APIAddSigner(req []APIAddSignerReq) (rsp *APIRsp[APIAddSignerRsp], err error) {
+	apiUrl := config.SerCfg.AsignCfg.Url + "/contract/addSigner"
+
+	reqArray := make([]map[string]interface{}, 0)
+	for _, item := range req {
+		reqArray = append(reqArray, structs.Map(item))
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqArray)
+	rspBody, err := HttpPost2(apiUrl, reqArray)
+	if err != nil {
+		logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
+		return
+	}
+	rspStr := string(rspBody)
+	if len(rspStr) == 0 {
+		logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
+		return
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
+	rsp = new(APIRsp[APIAddSignerRsp])
+	err = json.Unmarshal(rspBody, rsp)
+
+	return
+}
+
+// APIContractStatus 查询合同状态
+func APIContractStatus(req APIContractStatusReq) (rsp *APIRsp[APIContractStatusRsp], err error) {
+	apiUrl := config.SerCfg.AsignCfg.Url + "/contract/status"
+
+	reqMap := structs.Map(req)
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 请求, request:", reqMap)
+	rspBody, err := HttpPost(apiUrl, reqMap)
+	if err != nil {
+		logger.GetLogger().Error("调用接口 "+apiUrl+" 错误, error:", err.Error())
+		return
+	}
+	rspStr := string(rspBody)
+	if len(rspStr) == 0 {
+		logger.GetLogger().Error("调用接口 " + apiUrl + " 错误, response为空")
+		return
+	}
+	logger.GetLogger().Info("调用接口 "+apiUrl+" 返回, response:", rspStr)
+	rsp = new(APIRsp[APIContractStatusRsp])
 	err = json.Unmarshal(rspBody, rsp)
 
 	return

+ 223 - 37
services/asign/apiModels.go

@@ -1,7 +1,7 @@
 package asign
 
 type APIRspData interface {
-	interface{} | APIBankCard4Rsp | APIAddPersonalUserRsp | APICaptchaVerifyRsp | APIGetUserRsp
+	interface{} | APIBankCard4Rsp | APIAddUserRsp | APICaptchaVerifyRsp | APIGetUserRsp
 }
 
 type APIRsp[T APIRspData] struct {
@@ -54,55 +54,241 @@ type APICaptchaVerifyRsp struct {
 
 // APIGetUserReq 查询用户信息入参
 type APIGetUserReq struct {
-	Account    *string `json:"account"`    // 用户唯一识别码
-	CreditCode *string `json:"creditCode"` // 社会统一信用代码
-	IdCard     *string `json:"idCard"`     // 	证件号码
+	Account    string `json:"account" structs:",omitempty"`    // 用户唯一识别码
+	CreditCode string `json:"creditCode" structs:",omitempty"` // 社会统一信用代码
+	IdCard     string `json:"idCard" structs:",omitempty"`     // 证件号码
 }
 
 // APIGetUserRsp 查询用户信息出参
 type APIGetUserRsp struct {
-	Account      string `json:"account"`      //	用户账号,用户唯一识别码
-	Name         string `json:"name"`         //	个人用户姓名/企业法人姓名
-	CompanyName  string `json:"companyName"`  //	企业名称
-	IdCard       string `json:"idCard"`       //	个人用户证件号/企业法人身份证号
-	Mobile       string `json:"mobile"`       //	用户手机号(签约短信通知手机号)
-	Email        string `json:"email"`        //	用户邮箱号
-	UserType     int    `json:"userType"`     //	用户类型: 1:企业 2:个人
-	CreditCode   string `json:"creditCode"`   //	社会统一信用代码
-	BankCard     string `json:"bankCard"`     //	用户银行卡号
-	PortVersion  int    `json:"portVersion"`  //	用户添加时调用的接口版本: 0:历史接口 1:V2版本接口
-	IdentifyType int    `json:"identifyType"` //	认证类型
-	AuthType     int    `json:"authType"`     //	认证方式: 当portVersion=0 历史接口时 0:非强制认证 1:爱签平台强制认证 当portVersion=1 (V2)版本接口时 0:平台方自行认证 1:爱签平台认证
-	CreateTime   string `json:"createTime"`   //	创建时间
-	IdentifyTime string `json:"identifyTime"` //	认证时间
+	Account      string `json:"account"`      // 用户账号,用户唯一识别码
+	Name         string `json:"name"`         // 个人用户姓名/企业法人姓名
+	CompanyName  string `json:"companyName"`  // 企业名称
+	IdCard       string `json:"idCard"`       // 个人用户证件号/企业法人身份证号
+	Mobile       string `json:"mobile"`       // 用户手机号(签约短信通知手机号)
+	Email        string `json:"email"`        // 用户邮箱号
+	UserType     int    `json:"userType"`     // 用户类型: 1:企业 2:个人
+	CreditCode   string `json:"creditCode"`   // 社会统一信用代码
+	BankCard     string `json:"bankCard"`     // 用户银行卡号
+	PortVersion  int    `json:"portVersion"`  // 用户添加时调用的接口版本: 0:历史接口 1:V2版本接口
+	IdentifyType int    `json:"identifyType"` // 认证类型
+	AuthType     int    `json:"authType"`     // 认证方式: 当portVersion=0 历史接口时 0:非强制认证 1:爱签平台强制认证 当portVersion=1 (V2)版本接口时 0:平台方自行认证 1:爱签平台认证
+	CreateTime   string `json:"createTime"`   // 创建时间
+	IdentifyTime string `json:"identifyTime"` // 认证时间
 }
 
 // AddPersonalUserReq 添加个人用户(V2)入参
 type APIAddPersonalUserReq struct {
-	Account         string `json:"account" binding:"required"` // 用户唯一识别码(请转入UserID)
-	SerialNo        string `json:"serialNo"`                   // 实名认证流水号
-	Name            string `json:"name"`                       // 用户姓名
-	IdCard          string `json:"idCard"`                     // 个人身份证、台胞证、港澳通行证等证件号
-	IdCardType      int    `json:"idCardType"`                 // 证件类型 1:居民身份证 2:台湾居民来往内地通行证 3:港澳居民往来内地通行证 10:武装警察身份证 11:军人身份证 15:警察(警官)证 21:外国人永久居留证 23:护照
-	Mobile          string `json:"mobile"`                     // 手机号码
-	SignPwd         string `json:"signPwd"`                    // 签约密码(MTP2登录密码加密方式),如果为空将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)
-	IsSignPwdNotice int    `json:"isSignPwdNotice"`            // 是否将签约密码以短信形式通知用户 0:不通知(默认) 1:通知
-	IsNotice        int    `json:"isNotice"`                   // 用户发起合同或需要签署时是否进行短信通知 0:否(默认) 1:是
-}
-
-// AddPersonalUserRsp 添加个人用户(V2)出参
-type APIAddPersonalUserRsp struct {
+	Account         string `json:"account" binding:"required"`           // 用户唯一识别码(请转入UserID)
+	SerialNo        string `json:"serialNo" structs:",omitempty"`        // 实名认证流水号
+	Name            string `json:"name" structs:",omitempty"`            // 用户姓名
+	IdCard          string `json:"idCard" structs:",omitempty"`          // 个人身份证、台胞证、港澳通行证等证件号
+	IdCardType      int    `json:"idCardType" structs:",omitempty"`      // 证件类型 1:居民身份证 2:台湾居民来往内地通行证 3:港澳居民往来内地通行证 10:武装警察身份证 11:军人身份证 15:警察(警官)证 21:外国人永久居留证 23:护照
+	Mobile          string `json:"mobile" structs:",omitempty"`          // 手机号码
+	SignPwd         string `json:"signPwd" structs:",omitempty"`         // 签约密码(MTP2登录密码加密方式),如果为空将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)
+	IsSignPwdNotice int    `json:"isSignPwdNotice" structs:",omitempty"` // 是否将签约密码以短信形式通知用户 0:不通知(默认) 1:通知
+	IsNotice        int    `json:"isNotice" structs:",omitempty"`        // 用户发起合同或需要签署时是否进行短信通知 0:否(默认) 1:是
+}
+
+// APIAddEnterpriseUserReq 添加企业用户(V2)入参
+type APIAddEnterpriseUserReq struct {
+	Account         string `json:"account" binding:"required"`           // 用户唯一识别码(可用证件号、手机号等具有唯一属性的标识作为参数传递)
+	SerialNo        string `json:"serialNo" structs:",omitempty"`        // 实名认证流水号(若您希望不传此值,由您自行完成认证。请联系商务人员开通权限)
+	CompanyName     string `json:"companyName" structs:",omitempty"`     // 企业名称
+	CreditCode      string `json:"creditCode" structs:",omitempty"`      // 企业证件号
+	CreditType      int    `json:"creditType" structs:",omitempty"`      // 企业证件类型, 不传默认为1; 1:统一社会信用代码 2:表示其他证件类型
+	Name            string `json:"name" structs:",omitempty"`            // 企业法人姓名
+	IdCard          string `json:"idCard" structs:",omitempty"`          // 法人身份证、台胞证、港澳通行证等证件号
+	IdCardType      int    `json:"idCardType" structs:",omitempty"`      // 证件类型, 不传默认为1; 1:居民身份证 2:台湾居民来往大陆通行证 3:港澳居民来往内地通行证等...
+	Mobile          string `json:"mobile" structs:",omitempty"`          // 签约手机,该手机号将用于企业用户合同签署时短信验证,请确保真实有效
+	ContactName     string `json:"contactName" structs:",omitempty"`     // 联系人姓名(与企业的法定代表人可以是同一个人)
+	ContactIdCard   string `json:"contactIdCard" structs:",omitempty"`   // 联系人身份证号(与企业的法定代表人可以是同一个人)
+	SignPwd         string `json:"signPwd" structs:",omitempty"`         // 签约密码明文,如果为空我方将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)
+	IsSignPwdNotice int    `json:"isSignPwdNotice" structs:",omitempty"` // 是否将签约密码以短信形式通知用户: 0-不通知(默认), 1-通知
+	IsNotice        int    `json:"isNotice" structs:",omitempty"`        // 用户发起合同或需要签署时是否进行短信通知: 0-否(默认), 1-是
+}
+
+// APIAddUserRsp 添加用户(V2)出参(包括个人和企业)
+type APIAddUserRsp struct {
 	SealNo string `json:"sealNo"  binding:"required"` // 生成默认印章编号
 }
 
+// APITemplateListReq 查询模板列表入参
+type APITemplateListReq struct {
+	Page          int    `json:"page"`          // 页数(不传默认1)
+	Rows          int    `json:"rows"`          // 每页数据量(不传默认10)
+	TemplateIdent string `json:"templateIdent"` // 模板编号
+}
+
+// APITemplateInfo 模板信息
+type APITemplateInfo struct {
+	TemplateIdent string `json:"templateIdent"` // 模板编号
+	TemplateName  string `json:"templateName"`  // 模板名称
+	TemplateType  int    `json:"templateType"`  // 模板类型:1:word 2:pdf 3:html
+	Page          int    `json:"page"`          // 模板页数
+	Sponsor       bool   `json:"sponsor"`       // 是否含发起方填写
+	ReceiverFill  bool   `json:"receiverFill"`  // 是否含接收方填写
+	Param         bool   `json:"param"`         // 是否含填充参数
+	Sign          bool   `json:"sign"`          // 是否含签约参数
+	Status        int    `json:"status"`        // 模板状态:0:删除 1:使用中 2:停用
+	Url           string `json:"url"`           // 模板预览地址(有效时间30分钟)
+	SyncUrl       string `json:"syncUrl"`       // 同步模板预览地址(有效时间30分钟)
+	SyncStatus    int    `json:"syncStatus"`    // 模板同步状态:0:未同步 1:已同步 2:同步过时【注】此字段逻辑不针对老数据,当旧的模板再次同步后进入此逻辑
+	CreateTime    string `json:"createTime"`    // 创建时间
+	ModifyTime    string `json:"modifyTime"`    // 更新时间
+}
+
+// APITemplateListRsp 查询模板列表出参
+type APITemplateListRsp struct {
+	Total    int               `json:"total"`    // 总模板数量
+	PageNum  int               `json:"pageNum"`  // 页码
+	PageSize int               `json:"pageSize"` // 每页数据量
+	Size     int               `json:"size"`     // 当页数据量
+	Pages    int               `json:"pages"`    // 总页数
+	List     []APITemplateInfo `json:"list"`     // 模板列表
+}
+
+// APIFillData 单行文本、多行文本、日期、身份证类型参数填充。
+type APIFillData struct {
+	DataKey string `json:"dataKey" binding:"required"` // 参数名称
+	Value   string `json:"value" binding:"required"`   // 填充值
+}
+
+// APIComponentData 单选、复选、勾选、图片类型参数填充
+type APIComponentData struct {
+	Type         int                    `json:"type" binding:"required"`           // 组件类型: 2:单选 3:勾选 9:复选 11:图片
+	Keyword      string                 `json:"keyword" binding:"required"`        // 参数名称
+	DefaultValue string                 `json:"defaultValue" structs:",omitempty"` // 当填充类型为勾选(type=3)时填写: Yes:选中 Off:不选中
+	Options      map[string]interface{} `json:"options" structs:",omitempty"`      // 选项内容
+	ImageByte    []byte                 `json:"imageByte" structs:",omitempty"`    // 图片资源
+}
+
+// APItableData 表格填充数据
+type APItableData struct {
+	Keyword   string                   `json:"keyword" binding:"required"` // 表名称
+	RowValues []map[string]interface{} `json:"rowValues"`                  // 表格填充值
+}
+
+// APITemplate 合同模板
 type APITemplate struct {
-	TemplateNo string `json:"templateNo"` // 合同模板编号
+	TemplateNo string `json:"templateNo" binding:"required"` // 合同模板编号
+	// ContractNo    string             `json:"contractNo" structs:",omitempty"`    // 合同编号(此处可传已完成签署的合同编号,实现追加签章的场景)
+	// FillData      APIFillData        `json:"fillData" structs:",omitempty"`      // 单行文本、多行文本、日期、身份证类型参数填充。
+	// ComponentData []APIComponentData `json:"componentData" structs:",omitempty"` // 单选、复选、勾选、图片类型参数填充
+	// TableDatas    []APItableData     `json:"tableDatas" structs:",omitempty"`    // 表格填充数据
 }
 
+// APICreateContractReq 上传待签署文件入参
+//
+// 参数说明:https://preweb.asign.cn/platform/openDoc/docDetail?mid=createContract
 type APICreateContractReq struct {
-	ContractNo   string `json:"contractNo" binding:"required"`   // 合同ID,合同唯一编号
-	ContractName string `json:"contractName" binding:"required"` // 合同名称
-	ValidityTime int    `json:"validityTime"`                    // 合同签署剩余天数(系统当前时间+该天数=在此日期之前可以签署合同日期),【注】与合同有效截止日期必传其一,【例】可传剩余天数:15
-	ValidityDate string `json:"validityDate"`                    // 合同有效截止日期(在此日期之前可以签署合同,格式要求:yyyyMMddHHmmss),【注】与合同有效天数必传其一,【例】传值“20231207190000” 为:2023年12月07日19时00分00秒
-	SignOrder    int    `json:"signOrder" binding:"required"`    // 签约方式 1:无序签约(默认) 2:顺序签约
+	ContractNo           string        `json:"contractNo" binding:"required"`             // 合同ID,合同唯一编号
+	ContractName         string        `json:"contractName" binding:"required"`           // 合同名称
+	ValidityTime         int           `json:"validityTime" structs:",omitempty"`         // 合同签署剩余天数(系统当前时间+该天数=在此日期之前可以签署合同日期),【注】与合同有效截止日期必传其一,【例】可传剩余天数:15
+	ValidityDate         string        `json:"validityDate" structs:",omitempty"`         // 合同有效截止日期(在此日期之前可以签署合同,格式要求:yyyyMMddHHmmss),【注】与合同有效天数必传其一,【例】传值“20231207190000” 为:2023年12月07日19时00分00秒
+	SignOrder            int           `json:"signOrder" binding:"required"`              // 签约方式 1:无序签约(默认) 2:顺序签约
+	ReadSeconds          int           `json:"readSeconds" structs:",omitempty"`          // 强制阅读时间(秒)
+	ReadType             int           `json:"readType" structs:",omitempty"`             // 强制阅读设置 1:倒计时读秒方式 2:必须滑动到文件最底部(有多个文件务必逐个阅读) 3:必须点击打开查看(有多个文件务必逐个打开查看)【注】当readType不传值,仅readSeconds传值时,倒计时读秒是针对整体合同(不强制每个文件逐个阅读)。当readType传值1时,readSeconds也传值时,倒计时(要求每个文件逐个阅读)。当readType传值2或3时,readSeconds也传值时,倒计时读秒是针对整体合同(不强制每个文件逐个阅读)。
+	NeedAgree            int           `json:"needAgree" structs:",omitempty"`            // 同意协议开关:(开启后表示必须同意协议才可签署合同) 1 - 开,0 - 关(默认)
+	AutoExpand           int           `json:"autoExpand" structs:",omitempty"`           // 多文件时,是否自动展开文件列表 1 - 展开, 0 - 不展开(默认)
+	NotifyUrl            string        `json:"notifyUrl" structs:",omitempty"`            // 合同签署完成后(合同状态 status=2)回调通知地址,响应【"ok"】表示接收回调成功。
+	CallbackUrl          string        `json:"callbackUrl" structs:",omitempty"`          // 合同拒签或过期后(合同状态 status=3/4)回调通知地址,响应【"ok"】表示接收回调成功。
+	UserNotifyUrl        string        `json:"userNotifyUrl" structs:",omitempty"`        // 某个用户签署完成(用户签署状态 signStatus=2,参考 查询合同信息接口)之后回调地址,响应【"ok"】表示接收回调成功。
+	RedirectUrl          string        `json:"redirectUrl" structs:",omitempty"`          // 合同签署完成后同步回调地址: redirectUrl 若不为空,可以跳转业务方自己的前端过渡页面,实现业务方自己的逻辑。redirectUrl 为空,签署成功后,会回调小程序或app的方法。具体调用方法参考如下。
+	RefuseOn             int           `json:"refuseOn" structs:",omitempty"`             // 合同签署页退回按钮开关: 1 - 开启,0 - 关闭(默认)
+	AutoContinue         int           `json:"autoContinue" structs:",omitempty"`         // 当前签署人签署完成自动跳转至下一签署人签署开关(仅对顺序签合同生效): 1 - 开启,0 - 关闭(默认)
+	ViewFlg              int           `json:"viewFlg" structs:",omitempty"`              // 合同签署完是否允许可以通过链接查看合同内容: 1:不允许查看 不传值:可以查看(默认)
+	RedirectReturnUrl    string        `json:"redirectReturnUrl" structs:",omitempty"`    // 合同发起页面返回按钮跳转url 若不为空,可以跳转业务方自己的前端页面。
+	RedirectCompletedUrl string        `json:"redirectCompletedUrl" structs:",omitempty"` // 合同发起页面完成后跳转url 若不为空,可以跳转业务方自己的前端过渡页面,实现业务方自己的逻辑。
+	ContractFiles        []interface{} `json:"contractFiles" structs:",omitempty"`        // 合同附件(与合同模板必传其一)(支持多文件上传)
+	Templates            []APITemplate `json:"templates" structs:",omitempty"`            // 合同模板列表(与合同附件必传其一)
+}
+
+// APICreateContractRsp 上传待签署文件出参
+type APICreateContractRsp struct {
+	PreviewUrl    string        `json:"previewUrl"`    // 合同预览链接(预览链接3小时内有效,过期后可通过查询合同信息接口重新获取)
+	ContractFiles []interface{} `json:"contractFiles"` // 合同文件信息(文件名称,附件编号,页数)
+}
+
+// APISignStrategy 签章策略
+type APISignStrategy struct {
+	AttachNo     int     `json:"attachNo" binding:"required"`     // 附件编号 注:对应上传待签署文件接口(createContract)中,合同附件(contractFiles)或合同模板(templates)参数中的List排序序号(例如:1,2,3...)
+	LocationMode int     `json:"locationMode" binding:"required"` // 定位方式:2:坐标签章 3:关键字签章 4:模板坐标签章
+	CanDrag      int     `json:"canDrag" structs:",omitempty"`    // 签章位置是否可以拖动 1:可以, 其他值:不可以
+	SignKey      string  `json:"signKey" structs:",omitempty"`    // 关键字或签署区名称key(定位方式为关键字签章时此处需传定位关键字,定位方式为模板坐标签章时此处需传模板中设置的签署区名称)
+	SignType     int     `json:"signType" structs:",omitempty"`   // 印章类型:1:签名/签章(默认) 2:时间戳
+	SignPage     int     `json:"signPage" structs:",omitempty"`   // 签章页码(定位方式为坐标签章时必传)
+	SignX        float64 `json:"signX" structs:",omitempty"`      // 签章位置与当前签约文件的左内边距与当前签约文件宽度的比例(精确到小数点后2位)(定位方式为坐标签章时必传)
+	SignY        float64 `json:"signY" structs:",omitempty"`      // 签章位置与当前签约文件的上内边距与当前签约文件高度的比例(精确到小数点后2位)(定位方式为坐标签章时必传)
+	OffsetX      float64 `json:"offsetX" structs:",omitempty"`    // 坐标偏移量(像素PX)
+	OffsetY      float64 `json:"offsetY" structs:",omitempty"`    // 坐标偏移量(像素PX)
+}
+
+// APIReceiverFillStrategy 接收方模板填充策略
+type APIReceiverFillStrategy struct {
+	AttachNo  int           `json:"attachNo" binding:"required"`    // 附件编号(合同上传的附件序号:1,2,3…)
+	Key       string        `json:"key" binding:"required"`         // 参数名称
+	Value     string        `json:"value" structs:",omitempty"`     // ● 填充类型为单行、多行、身份证、日期时传null或空字符串则为页面填充,传值则为即时填充 ● 填充类型为勾选时,Yes:选中;Off:不选中 ● 填充类型为图片时,传base64字符串
+	FillStage int           `json:"fillStage" structs:",omitempty"` // 当填充类型为单选、复选、勾选、图片时,填充场景标记:2:即时填充(调用当前接口即刻填充,默认) 3:页面填充(用户签约时填充)
+	Options   []interface{} `json:"options" structs:",omitempty"`   // 单、复选选项内容
+	RowValues []interface{} `json:"rowValues" structs:",omitempty"` // 表格填充值
+}
+
+// APIAddSignerReq 添加签署方入参
+//
+// 参数说明:https://preweb.asign.cn/platform/openDoc/docDetail?mid=addSigner
+type APIAddSignerReq struct {
+	ContractNo               string                    `json:"contractNo" binding:"required"`                 // 合同唯一编码 (40位之内)
+	Account                  string                    `json:"account" binding:"required"`                    // 用户唯一识别码
+	SignType                 int                       `json:"signType" binding:"required"`                   // 签约方式:2:无感知签约(需要开通权限) 3:有感知签约
+	SealNo                   string                    `json:"sealNo" structs:",omitempty"`                   // 印章编号【注】若不传值,则由当前主体的默认印章进行签署
+	AuthSignAccount          string                    `json:"authSignAccount" structs:",omitempty"`          // 指定授权签约用户,该用户需要有印章编号【sealNo】的有效授权记录,如若不指定则印章的默认使用者进行签署,如无默认使用者,则由当前主体【account】进行签署
+	NoticeMobile             string                    `json:"noticeMobile" structs:",omitempty"`             // 通知手机号(用于接收合同签署链接的通知短信)
+	NoticeEmail              string                    `json:"noticeEmail" structs:",omitempty"`              // 通知邮箱号(用于接收合同签署链接的通知短信)
+	SignOrder                string                    `json:"signOrder" structs:",omitempty"`                // 使用顺序签约时签约顺序编号(从1开始),无序签约都为1
+	IsNotice                 int                       `json:"isNotice" structs:",omitempty"`                 // 是否接收合同签署链接的短信通知,优先级高于添加用户接口同名参数:0 - 否(默认),1 - 是
+	ValidateType             int                       `json:"validateType" structs:",omitempty"`             // 签署方式指定:(从以下分类中指定一种) 1:短信验证码签约(支持企业和个人) 2:签约密码签约(支持企业和个人) 3:人脸识别签约(支持企业和个人) 4:手写签名(不推荐,仅限个人,需要开通权限) 5:宋体章签名(不推荐,仅限个人,需要开通权限) 6:手写识别签名+短信签约(仅限个人) 7:手写签名+短信签约(仅限个人) 8:手写签名+人脸识别签约(仅限个人) 9:手写识别签名+人脸识别签约(仅限个人) 10:手写签名 + 认证意愿合一(仅支持个人陌生用户) 11:手写签名识别 + 认证意愿合一(仅支持个人陌生用户) 12:宋体章 + 认证意愿合一(仅支持个人陌生用户) 13:视频双录核身签约(需要开通权限)
+	FaceAuthMode             int                       `json:"faceAuthMode" structs:",omitempty"`             // 人脸识别方式:1:支付宝(不可在支付宝小程序中接入) 2:H5(默认) 4:微信小程序(支持在微信小程序内唤起人脸识别,需联系商务人员开启权限后使用) 5:支付宝小程序(支持在支付宝小程序内唤起人脸识别,需联系商务人员开启权限后使用) 【注】签署方式包含人脸(3,8,9)时,可指定人脸识别方式,不传默认为H5
+	ValidateTypeList         string                    `json:"validateTypeList" structs:",omitempty"`         // 组合签署方式指定:(从以上分类中指定多种以逗号间隔,示例:1,2,3)。允许开发者可以自主控制展示几种签署方式,让签约用户选择。【注】 validateTypeList和validateType都有传值时,签署方式按照validateTypeList指定
+	AutoSwitch               int                       `json:"autoSwitch" structs:",omitempty"`               // 自动切换签约方式:开发者可以自主控制手写内容识别和人脸刷脸识别多次不通过时,是否允许用户切换方式 1 - 仅手写识别允许切换(默认) 2 - 仅人脸识别允许切换 3 - 全部允许 0 - 全部不允许 【注】手写识别三次失败时,会允许用户切换成宋体印章。人脸识别三次不通过,允许切换为短信验证码方式。
+	IsNoticeComplete         int                       `json:"isNoticeComplete" structs:",omitempty"`         // 合同签署完成后是否通知用户:1 - 是,0 - 否(默认)
+	WaterMark                int                       `json:"waterMark" structs:",omitempty"`                // 是否在距底部10px中央位置添加日期水印: 1 - 是,0 - 否(默认)
+	AutoSms                  int                       `json:"autoSms" structs:",omitempty"`                  // 是否自动触发验证码短信:(仅短信验证码方式签署时生效)1:是(默认) 0:否(需要用户手动点击“获取验证码”触发)
+	CustomSignFlag           int                       `json:"customSignFlag" structs:",omitempty"`           // 签章位置策略:0(默认)- 由该接口的参数signStrategyList或signStrikeList指定 1 - 签署用户在签署时自行拖动签章位置 2 - 签署用户在签署时自行拖动签章位置和骑缝章位置
+	IsIframe                 int                       `json:"isIframe" structs:",omitempty"`                 // 如果认证页面使用了iframe,且签约涉及人脸识别,则需传入此参数 1.是 0.否(默认) 接入方需要给iframe开启相机权限,方可正常使用实时检测人脸核身功能<iframe allow="camera;"></iframe>
+	SignStrategyList         []APISignStrategy         `json:"signStrategyList" binding:"required"`           // 签章策略
+	SignStrikeList           []interface{}             `json:"signStrikeList" structs:",omitempty"`           // 骑缝章策略
+	ReceiverFillStrategyList []APIReceiverFillStrategy `json:"receiverFillStrategyList" structs:",omitempty"` // 接收方模板填充策略
+	AuthConfig               interface{}               `json:"authConfig" structs:",omitempty"`               // 添加陌生签署人认证参数配置
+}
+
+// APISignUserDetail 合同用户信息
+type APISignUserDetail struct {
+	Account    string `json:"account" binding:"required"`     // 用户唯一识别码
+	SignUrl    string `json:"signUrl" binding:"required"`     // 合同签署链接
+	PwdSignUrl string `json:"pwdSignUrl" binding:"required"`  // 密码签署链接
+	SignOrder  int    `json:"signOrder" structs:",omitempty"` // 顺序签约的序号
+	Name       string `json:"name" binding:"required"`        // 用户姓名
+	IdCard     string `json:"idCard" binding:"required"`      // 用户身份证
+}
+
+// APIAddSignerRsp 添加签署方出参
+type APIAddSignerRsp struct {
+	ContractNo   string              `json:"contractNo"`   // 合同编号
+	ContractName string              `json:"contractName"` // 合同名称
+	ValidityTime string              `json:"validityTime"` // 合同有效期
+	PreviewUrl   string              `json:"previewUrl"`   // 合同预览链接
+	SignUser     []APISignUserDetail `json:"signUser"`     // 合同用户信息
+}
+
+// APIContractStatusReq 查询合同状态入参
+type APIContractStatusReq struct {
+	ContractNo string `json:"contractNo" binding:"required"` // 合同唯一编码
+}
+
+// APIContractStatusRsp 查询合同状态出参
+type APIContractStatusRsp struct {
+	ContractNo   string `json:"contractNo"`   // 合同唯一编号
+	ContractName string `json:"contractName"` // 合同名称
+	Status       int    `json:"status"`       // 合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常
 }

+ 1 - 1
services/asign/const.go

@@ -1,5 +1,5 @@
 package asign
 
 var (
-	CODE_SUCCESS = 10000 // 成功
+	CODE_SUCCESS = 100000 // 成功
 )

+ 91 - 25
services/asign/http.go

@@ -17,6 +17,7 @@ import (
 	"mtp2_if/config"
 	"mtp2_if/logger"
 	"net/http"
+	"reflect"
 	"sort"
 	"strconv"
 	"strings"
@@ -31,7 +32,7 @@ func HttpPost(apiUrl string, bizData map[string]interface{}) (rspBody []byte, er
 	privateKey := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", config.SerCfg.AsignCfg.PrivateKey)
 
 	// fuck asign dev.
-	timestamp := strconv.Itoa(int(time.Now().UnixMilli() + 1000*60))
+	timestamp := strconv.Itoa(int(time.Now().UnixMilli() + 10000*60))
 
 	// 签名
 	sortedData := sortMapByKey(bizData)
@@ -68,6 +69,56 @@ func HttpPost(apiUrl string, bizData map[string]interface{}) (rspBody []byte, er
 	return
 }
 
+func HttpPost2(apiUrl string, bizData []map[string]interface{}) (rspBody []byte, err error) {
+	appId := config.SerCfg.AsignCfg.AppId
+	privateKey := fmt.Sprintf("-----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY-----", config.SerCfg.AsignCfg.PrivateKey)
+
+	// fuck asign dev.
+	timestamp := strconv.Itoa(int(time.Now().UnixMilli() + 10000*60))
+
+	// 签名
+	sortedData := "["
+	for i, item := range bizData {
+		if i > 0 {
+			sortedData += ","
+		}
+		sortedData += sortMapByKey(item)
+	}
+	sortedData += "]"
+
+	signature, err := getSignature(sortedData, appId, timestamp, privateKey)
+	if err != nil {
+		logger.GetLogger().Errorf("[asign.HttpPost] 签名失败:" + err.Error())
+		return
+	}
+
+	// 构建form-data请求参数
+	var requestBody bytes.Buffer
+	multipartWriter := multipart.NewWriter(&requestBody)
+	multipartWriter.WriteField("appId", appId)
+	multipartWriter.WriteField("timestamp", timestamp)
+	multipartWriter.WriteField("bizData", sortedData)
+	multipartWriter.Close()
+	// 构建请求
+	req, err := http.NewRequest("POST", apiUrl, &requestBody)
+	// 设置请求头
+	req.Header.Set("sign", signature)
+	req.Header.Set("timestamp", timestamp)
+	req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
+
+	// 调用接口
+	client := &http.Client{}
+	rsp, err := client.Do(req)
+	if err != nil {
+		logger.GetLogger().Errorf("[asign.HttpPost] 调用接口失败:" + err.Error())
+		return
+	}
+	defer rsp.Body.Close()
+	rspBody, err = io.ReadAll(rsp.Body)
+
+	return
+}
+
 // 签名规范:
 // 1、表单提交方式:form-data
 // 示例:1B2M2Y8AsgTpgAmY7PhCfg==
@@ -133,34 +184,49 @@ func sortMapByKey(data map[string]interface{}) (sortedData string) {
 		if i > 0 {
 			sortedData += ","
 		}
-		switch data[k].(type) {
-		case string:
-			sortedData += fmt.Sprintf(`"%s":"%s"`, k, data[k].(string))
-		case map[string]interface{}:
-			sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(data[k].(map[string]interface{})))
-		case []interface{}:
-			list := data[k].([]interface{})
-			sortedData += fmt.Sprintf(`"%s":[`, k)
-			for j, item := range list {
-				if j > 0 {
-					sortedData += ","
+
+		// 判断是否指针
+		v := reflect.ValueOf(data[k])
+		if v.Kind() == reflect.Ptr {
+			switch data[k].(type) {
+			case *string:
+				sortedData += fmt.Sprintf(`"%s":"%s"`, k, *(data[k].(*string)))
+			case *map[string]interface{}:
+				sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(*(data[k].(*map[string]interface{}))))
+			case *[]interface{}:
+				list := data[k].([]interface{})
+				sortedData += fmt.Sprintf(`"%s":[`, k)
+				for j, item := range list {
+					if j > 0 {
+						sortedData += ","
+					}
+					sortedData += sortMapByKey(item.(map[string]interface{}))
 				}
-				sortedData += sortMapByKey(item.(map[string]interface{}))
+				sortedData += "]"
+			default:
+				sortedData += fmt.Sprintf(`"%s":%v`, k, reflect.ValueOf(data[k]).Elem())
+			}
+		} else {
+			switch data[k].(type) {
+			case string:
+				sortedData += fmt.Sprintf(`"%s":"%s"`, k, data[k].(string))
+			case map[string]interface{}:
+				sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(data[k].(map[string]interface{})))
+			case []interface{}:
+				list := data[k].([]interface{})
+				sortedData += fmt.Sprintf(`"%s":[`, k)
+				for j, item := range list {
+					if j > 0 {
+						sortedData += ","
+					}
+					sortedData += sortMapByKey(item.(map[string]interface{}))
+				}
+				sortedData += "]"
+			default:
+				sortedData += fmt.Sprintf(`"%s":%v`, k, data[k])
 			}
-			sortedData += "]"
-		default:
-			sortedData += fmt.Sprintf(`"%s":%v`, k, data[k])
 		}
 	}
 
 	return fmt.Sprintf("{%s}", sortedData)
 }
-
-// func main() {
-// 	datas := make(map[string]interface{})
-// 	json.Unmarshal([]byte(`{"account":"12345","name":"张三","map":{"ccc":"adfasd","aaa":34355},"list":[{"ccc":"adfasd","aaa":34355},{"dddd":"8ghg","kkkk":12.55}]}`), &datas)
-// 	getSignature(datas, "290912417", "1701866011940",
-// 		`-----BEGIN PRIVATE KEY-----
-// MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAkMD+72J6iAF0ZNV+3t628lsRHfJ80nKZWK5/C7Pg+AZmOIzJlwHsKhRzCvxoxqYHQprhiFzW9l73v9vD9l1JYwIDAQABAkBVijccr01JYdKuY5t9iI8D2NzcnZc1pZMI3NUmzT18Uyg7b9CUvGHlLeg/gdT4QtVd7wIzHYCY4letEcEMh54BAiEAwzNWusj5XiLmty7PI0Hbakx4HtcND1+P0UHLEWqWOuECIQC91zQuL7nStgGzT3HvaeBB5Ouapa39fHRm2nCjHaxwwwIgRR2XdvmUOj23XWMomr5F14SN/7V7fVcD0D8wjNElsmECIDYavV5kb7tj7/wgqkInlKhzC8rZaUsTS0F9BBkY/eptAiAQJ8Saz8YlMIESdHMxANGSog01fECbcZqLFMuNf8SorA==
-// -----END PRIVATE KEY-----`)
-// }

+ 52 - 10
services/asign/models.go

@@ -4,20 +4,23 @@ import "time"
 
 // PersonBankCard4 个人银行卡四要素
 type PersonBankCard4 struct {
-	RealName string `json:"realName"` // 真实姓名
-	IdCardNo string `json:"idCardNo"` // 身份证号
-	BankCard string `json:"bankCard"` // 银行卡号(仅限印有“银联”字样的银行卡)
-	Mobile   string `json:"mobile"`   // 手机号码(限中国大陆11位手机号)
+	RealName           string `json:"realName"`           // 真实姓名
+	IdCardNo           string `json:"idCardNo"`           // 身份证号
+	BankCard           string `json:"bankCard"`           // 银行卡号(仅限印有“银联”字样的银行卡)
+	Mobile             string `json:"mobile"`             // 手机号码(限中国大陆11位手机号)
+	IdCardPhotoURL     string `json:"idCardPhoto"`        // 证件照正面
+	IdCardPhotoBackURL string `json:"idCardPhotoBackURL"` // 证件照背面
 }
 
 // CompanyBankCard4 企业法人银行卡四要素
 type CompanyBankCard4 struct {
-	CompanyName string `json:"companyName"` // 企业名称
-	CreditCode  string `json:"creditCode"`  // 社会统一信用代码
-	RealName    string `json:"realName"`    // 法人姓名
-	IdCardNo    string `json:"idCardNo"`    // 法人身份证号
-	BankCard    string `json:"bankCard"`    // 法人银行卡号(仅限印有“银联”字样的银行卡)
-	Mobile      string `json:"mobile"`      // 法人手机号(限中国大陆11位手机号)
+	CompanyName    string `json:"companyName"` // 企业名称
+	CreditCode     string `json:"creditCode"`  // 社会统一信用代码
+	RealName       string `json:"realName"`    // 法人姓名
+	IdCardNo       string `json:"idCardNo"`    // 法人身份证号
+	BankCard       string `json:"bankCard"`    // 法人银行卡号(仅限印有“银联”字样的银行卡)
+	Mobile         string `json:"mobile"`      // 法人手机号(限中国大陆11位手机号)
+	IdCardPhotoURL string `json:"idCardPhoto"` // 营业执照
 }
 
 // 银行卡四要素认证入参
@@ -33,7 +36,46 @@ type BankCard4Rsp struct {
 	SerialNo string `json:"serialNo"` // 认证流水号
 }
 
+// 重新发送认证验证码入参
 type CaptchaResendReq struct {
 	SerialNo  string    `json:"serialNo"`  // 认证流水号
 	TimeStamp time.Time `json:"timeStamp"` // 时间戳,可不传(S1016)
 }
+
+// 认证验证码校验入参
+type CaptchaVerifyReq struct {
+	UserId   int    `json:"userId" binding:"required"`   // 用户ID
+	Type     int    `json:"type" binding:"required"`     // 实体类型 1:个人 2:企业
+	SerialNo string `json:"serialNo" binding:"required"` // 认证流水号
+	Captcha  string `json:"captcha" binding:"required"`  // 短信验证码
+}
+
+type QueryUsereSignRecordsReq struct {
+	UserId           int  `form:"userId" binding:"required"`       // 用户ID
+	MemberUserId     int  `form:"memberUserId" binding:"required"` // 所属会员ID
+	RecordId         *int `form:"recordId"`                        // 记录ID
+	TemplateConfigId *int `form:"templateConfigId"`                // 模板配置ID
+	Templatetype     *int `form:"templatetype"`                    // 模板类型 - 1:实名认证 2:开户协议 3:日结算单 4:交易协议
+}
+
+// 创建合同入参
+type CreateContractReq struct {
+	RecordId int64 `json:"recordId" binding:"required"` // 用户电子签记录表记录ID
+}
+
+// 创建合同出参
+type CreateContractRsp struct {
+	SignUrl string `json:"signUrl"` // 合同签署链接
+}
+
+// 同步合同状态入参
+type SyncContractStatusReq struct {
+	RecordId int64 `json:"recordId" binding:"required"` // 用户电子签记录表记录ID
+}
+
+// 同步合同状态出参
+type SyncContractStatusRsp struct {
+	ContractNo   string `json:"contractNo"`   // 合同唯一编号
+	ContractName string `json:"contractName"` // 合同名称
+	Status       int    `json:"status"`       // 爱签合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常
+}

+ 506 - 6
services/asign/servcies.go

@@ -1,10 +1,17 @@
 package asign
 
 import (
+	"bytes"
+	"encoding/json"
 	"errors"
+	"fmt"
+	"io"
+	"mtp2_if/config"
 	"mtp2_if/db"
+	"mtp2_if/logger"
 	"mtp2_if/models"
 	"mtp2_if/utils"
+	"net/http"
 	"strconv"
 )
 
@@ -22,42 +29,51 @@ func BankCard4(req BankCard4Req) (rsp BankCard4Rsp, err error) {
 
 	// 判断证件号码是否已经在爱签平台存在
 	var getUserReq APIGetUserReq
-	getUserReq.Account = utils.SetPointValue(strconv.Itoa(req.UserId))
+	getUserReq.Account = strconv.Itoa(req.UserId)
 	apiRsp, err := APIGetUser(getUserReq)
 	if err != nil {
 		return
 	}
 	if apiRsp.Code == CODE_SUCCESS {
 		err = errors.New("电子签平台用户编号已存在")
+		logger.GetLogger().Error("电子签平台用户编号已存在, apiRsp:", apiRsp)
 		return
 	}
-	getUserReq.Account = nil
+	getUserReq.Account = ""
 	if req.Type == 1 {
-		getUserReq.IdCard = utils.SetPointValue(req.Person.IdCardNo)
+		getUserReq.IdCard = req.Person.IdCardNo
 	} else {
-		getUserReq.CreditCode = utils.SetPointValue(req.Company.CreditCode)
+		getUserReq.CreditCode = req.Company.CreditCode
 	}
 	apiRsp, err = APIGetUser(getUserReq)
 	if err != nil {
 		return
 	}
-	if apiRsp.Code == CODE_SUCCESS {
+	if apiRsp.Code == CODE_SUCCESS && len(apiRsp.Data) > 0 {
 		err = errors.New("电子签平台证件号码已存在")
+		logger.GetLogger().Error("电子签平台证件号码已存在, apiRsp:", apiRsp)
 		return
 	}
 
 	// 从交易库中获取类型为实名认证的电子签信息
 	var record models.Useresignrecord
-	has, err := db.GetEngine().Where("TEMPLATETYPE = 1 AND USERID = ?").Get(&record)
+	has, err := db.GetEngine().Where("TEMPLATETYPE = 1 AND USERID = ?", req.UserId).Get(&record)
 	if err != nil {
 		return
 	}
 	if !has {
 		err = errors.New("无对应实名认证记录信息")
+		logger.GetLogger().Error("无对应实名认证记录信息, userId:", req.UserId)
+		return
+	}
+	if record.RECORDSTATUS == 3 {
+		err = errors.New("账户已实名")
+		logger.GetLogger().Error("账户已实名, userId:", req.UserId)
 		return
 	}
 
 	// 调用爱签接口
+	var authinfo []byte
 	var bankCard4Rsp *APIRsp[APIBankCard4Rsp]
 	if req.Type == 1 { // 个人
 		personBankCard4Req := APIPersonBankCard4Req{
@@ -69,6 +85,9 @@ func BankCard4(req BankCard4Req) (rsp BankCard4Rsp, err error) {
 		if bankCard4Rsp, err = APIPersonBankCard4(personBankCard4Req); err != nil {
 			return
 		}
+		if authinfo, err = json.Marshal(req.Person); err != nil {
+			return
+		}
 	} else { // 企业
 		companyBankCard4Req := APICompanyBankCard4Req{
 			CompanyName: req.Company.CompanyName,
@@ -81,23 +100,504 @@ func BankCard4(req BankCard4Req) (rsp BankCard4Rsp, err error) {
 		if bankCard4Rsp, err = APICompanyBankCard4(companyBankCard4Req); err != nil {
 			return
 		}
+		if authinfo, err = json.Marshal(req.Company); err != nil {
+			return
+		}
 	}
 	if bankCard4Rsp.Code != CODE_SUCCESS {
 		err = errors.New(bankCard4Rsp.Msg)
 		return
 	}
 	rsp.SerialNo = bankCard4Rsp.Data.SerialNo
+	// 更新用户电子签记录-记录实名信息
+	sql := fmt.Sprintf(`
+		UPDATE useresignrecord
+		SET RECORDSTATUS = 2,
+			UPDATETIME = SYSDATE,
+			AUTHINFO = '%v'
+		WHERE USERID = %v AND TEMPLATETYPE = 1 
+	`, string(authinfo), req.UserId)
+	_, err = db.GetEngine().Exec(sql)
 
 	return
 }
 
+// CaptcaResend 重新发送认证验证码
 func CaptcaResend(req CaptchaResendReq) (err error) {
 	apiReq := APICaptchaResendReq{SerialNo: req.SerialNo}
 	apiRsp, err := APICaptchaResend(apiReq)
+	if err != nil {
+		return
+	}
+	if apiRsp.Code != CODE_SUCCESS {
+		err = errors.New(apiRsp.Msg)
+		return
+	}
+
+	return
+}
+
+// CaptchaVerify 认证验证码校验
+func CaptchaVerify(req CaptchaVerifyReq) (err error) {
+	// 从交易库中获取类型为实名认证的电子签信息
+	var record models.Useresignrecord
+	has, err := db.GetEngine().Where("TEMPLATETYPE = 1 AND RECORDSTATUS = 2 AND USERID = ?", req.UserId).Get(&record)
+	if err != nil {
+		return
+	}
+	if !has {
+		err = errors.New("无对应实名认证记录信息")
+		logger.GetLogger().Error("无对应实名认证记录信息, userId:", req.UserId)
+		return
+	}
+
+	// 调用爱签接口 - 认证验证码校验
+	apiReq := APICaptchaVerifyReq{
+		SerialNo: req.SerialNo,
+		Captcha:  req.Captcha,
+	}
+	apiRsp, err := APICaptchaVerify(apiReq)
+	if err != nil {
+		return
+	}
+	if apiRsp.Code != CODE_SUCCESS {
+		err = errors.New(apiRsp.Msg)
+		return
+	}
+
+	// 调用爱签接口 - 添加用户
+	var addUserRsp *APIRsp[APIAddUserRsp]
+	if req.Type == 1 { // 个人
+		addPersonalUserReq := APIAddPersonalUserReq{
+			Account:  strconv.Itoa(req.UserId),
+			SerialNo: req.SerialNo,
+		}
+		if addUserRsp, err = APIAddPersonalUser(addPersonalUserReq); err != nil {
+			return
+		}
+	} else { // 企业
+		addEnterpriseUserReq := APIAddEnterpriseUserReq{
+			Account:  strconv.Itoa(req.UserId),
+			SerialNo: req.SerialNo,
+		}
+		if addUserRsp, err = APIAddEnterpriseUser(addEnterpriseUserReq); err != nil {
+			return
+		}
+	}
+	if addUserRsp.Code != CODE_SUCCESS {
+		err = errors.New(addUserRsp.Msg)
+		return
+	}
+
+	// 获取临时存储的用户认证信息
+	cacheMap := make(map[string]interface{})
+	if err = json.Unmarshal([]byte(record.AUTHINFO), &cacheMap); err != nil {
+		logger.GetLogger().Error("反序列化临时存储用户信息失败, AUTHINFO:", record.AUTHINFO)
+		return
+	}
+	// 调用JAVA实名认证接口
+	reqParam := make(map[string]interface{})
+	if req.Type == 1 { // 个人
+		reqParam["userid"] = req.UserId
+		reqParam["cardnum"] = cacheMap["idCardNo"]
+		reqParam["username"] = cacheMap["realName"]
+		reqParam["cardtype"] = 0 // 目前写死证件类型为身份证 - 0
+		reqParam["cardfrontphotourl"] = cacheMap["idCardPhoto"]
+		reqParam["cardbackphotourl"] = cacheMap["idCardPhotoBackURL"]
+		reqParam["userinfotype"] = 1 // 1 - 个人
+	} else {
+		reqParam["userid"] = req.UserId
+		reqParam["customername"] = cacheMap["companyName"]
+		reqParam["cardtype"] = 21
+		reqParam["cardfrontphotourl"] = cacheMap["idCardPhoto"]
+		reqParam["legalpersonname"] = cacheMap["realName"]
+		reqParam["cardnum"] = cacheMap["creditCode"]
+		reqParam["mobilephone"] = cacheMap["mobile"]
+	}
+	jsonParam, err := json.Marshal(&reqParam)
+	if err != nil {
+		logger.GetLogger().Error("反序列化JAVA实名认证入参失败, reqParam:", reqParam)
+		return
+	}
+	// 构建请求
+	javaUrl := config.SerCfg.AsignCfg.OpenApiUrl + "/onlineopen/userInfo/addAuth"
+	javaReq, err := http.NewRequest("POST", javaUrl, bytes.NewReader(jsonParam))
+	// 设置请求头
+	javaReq.Header.Set("Content-Type", "application/json; charset=utf-8")
+	client := &http.Client{}
+	rsp, err := client.Do(javaReq)
+	if err != nil {
+		logger.GetLogger().Error("JAVA实名认证请求失败, err:", err)
+		return
+	}
+	defer rsp.Body.Close()
+	body, err := io.ReadAll(rsp.Body)
+	if err != nil {
+		logger.GetLogger().Error("JAVA实名认证请求获取body失败, err:", err)
+		return
+	}
+	// rspData: map[code:0 hasAuth:1 message:认证成功]
+	rspData := make(map[string]interface{})
+	if err = json.Unmarshal(body, &rspData); err != nil {
+		logger.GetLogger().Error("JAVA实名认证请求反序列化body失败, err:", err)
+		return
+	}
+	logger.GetLogger().Info("调用JAVA实名认证接口返回, rspData:", rspData)
+	code, ok := rspData["code"]
+	if !ok {
+		err = errors.New("实名认证失败,请稍后重试")
+		logger.GetLogger().Error(err.Error())
+		return
+	}
+	if code != "0" {
+		err = fmt.Errorf("实名认证失败,%v", rspData["message"])
+		logger.GetLogger().Error(err.Error())
+		return
+	}
+
+	// 更新用户电子签记录 - 更新实名认证状态
+	sql := fmt.Sprintf(`
+		UPDATE useresignrecord
+		SET RECORDSTATUS = 3,
+			UPDATETIME = SYSDATE
+		WHERE USERID = %v AND TEMPLATETYPE = 1 
+	`, req.UserId)
+	_, err = db.GetEngine().Exec(sql)
+
+	return
+}
+
+// SyncContractStatus 同步合同状态
+func SyncContractStatus(req SyncContractStatusReq) (rsp SyncContractStatusRsp, err error) {
+	// 从交易库中获取类型为实名认证的电子签信息
+	var record models.Useresignrecord
+	has, err := db.GetEngine().Where("RECORDID = ?", req.RecordId).Get(&record)
+	if err != nil {
+		return
+	}
+	if !has {
+		err = errors.New("查无此记录信息")
+		logger.GetLogger().Error("查无此记录信息, RecordId:", req.RecordId)
+		return
+	}
+	if record.CONTRACTNO == "" {
+		err = errors.New("此记录未生成合同编号")
+		logger.GetLogger().Error("此记录未生成合同编号, RecordId:", req.RecordId)
+		return
+	}
+
+	// 调用爱签接口 - 查询合同状态
+	apiReq := APIContractStatusReq{ContractNo: record.CONTRACTNO}
+	apiRsp, err := APIContractStatus(apiReq)
+	if err != nil {
+		return
+	}
+	if apiRsp.Code != CODE_SUCCESS {
+		err = errors.New(apiRsp.Msg)
+		return
+	}
+
+	status := record.RECORDSTATUS // 记录状态: 1:未签署 2:签署中 3:已签署 4:签署拒绝
+	switch apiRsp.Data.Status {   // 合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常
+	case 0:
+		status = 1
+	case 1:
+		status = 2
+	case 2:
+		status = 3
+	case 4:
+		status = 4
+	}
+
+	// 更新用户电子签记录 - 更新合同签署状态
+	sql := fmt.Sprintf(`
+		UPDATE useresignrecord
+		SET RECORDSTATUS = %v,
+			UPDATETIME = SYSDATE
+		WHERE RECORDID = %v
+	`, status, req.RecordId)
+	_, err = db.GetEngine().Exec(sql)
+	if err != nil {
+		return
+	}
+
+	rsp = SyncContractStatusRsp{
+		ContractNo:   apiRsp.Data.ContractNo,
+		ContractName: apiRsp.Data.ContractName,
+		Status:       apiRsp.Data.Status,
+	}
+
+	return
+}
+
+// PARTYA_SIGNATURE
+// PARTYA_DATE
+//
+// P_PARTYB_SIGNATURE
+// P_PARTYB_ID
+// P_PARTYB_MOBILE
+// P_PARTYB_DATE
+//
+// E_PARTYB_SIGNATURE
+// E_PARTYB_LEGAL
+// E_PARTYB_DATE
+
+// CreateContract 创建合同
+func CreateContract(req CreateContractReq) (rsp CreateContractRsp, err error) {
+	// 获取电子签信息
+	var record models.Useresignrecord
+	has, err := db.GetEngine().Where("RECORDID = ?", req.RecordId).Get(&record)
+	if err != nil {
+		logger.GetLogger().Error("获取电子签信息失败, err", err)
+		err = errors.New("获取电子签信息失败")
+		return
+	}
+	if !has {
+		err = errors.New("查无此记录信息")
+		logger.GetLogger().Error("查无此记录信息, RecordId:", req.RecordId)
+		return
+	}
+	if record.RECORDSTATUS != 1 {
+		err = errors.New("记录信息状态异常")
+		logger.GetLogger().Error("记录信息状态异常, RecordId:", req.RecordId, record.RECORDSTATUS)
+		return
+	}
+
+	// // 获取电子签模板字段配置信息
+	// fields := make([]models.Esigntemplatefield, 0)
+	// if err = db.GetEngine().Where("TEMPLATECONFIGID = ?", record.TEMPLATECONFIGID).Find(&fields); err != nil {
+	// 	logger.GetLogger().Error("获取电子签模板字段配置信息失败, err", err)
+	// 	err = errors.New("获取电子签模板字段配置信息失败")
+	// 	return
+	// }
+	// if len(fields) == 0 {
+	// 	err = errors.New("获取电子签模板字段配置信息异常")
+	// 	logger.GetLogger().Error("获取电子签模板字段配置信息异常, templateconfigid:", record.TEMPLATECONFIGID)
+	// 	return
+	// }
+
+	// 调用爱签接口 - 查询模板列表
+	apiReq := APITemplateListReq{Page: 1, Rows: 10}
+	apiRsp, err := APITemplateList(apiReq)
+	if err != nil {
+		return
+	}
 	if apiRsp.Code != CODE_SUCCESS {
 		err = errors.New(apiRsp.Msg)
 		return
 	}
+	if len(apiRsp.Data.List) == 0 {
+		err = errors.New("获取查询模板列表失败")
+		logger.GetLogger().Error("获取查询模板列表失败")
+		return
+	}
+
+	// 获取用户信息
+	userInfo, err := models.GetUserInfo(int(record.USERID))
+	if err != nil {
+		logger.GetLogger().Error("获取用户信息失败, err:", err)
+		err = errors.New("获取用户信息失败")
+		return
+	}
+	templateName := record.TEMPLATENAME
+	if userInfo.Userinfotype == 1 { // 个人
+		templateName += "-个人"
+	} else { // 企业
+		templateName += "-企业"
+	}
+	// 获取模板信息
+	templateIdent := ""
+	for _, item := range apiRsp.Data.List {
+		if item.TemplateName == templateName {
+			templateIdent = item.TemplateIdent
+			break
+		}
+	}
+	if templateIdent == "" {
+		err = errors.New("获取模板信息失败")
+		logger.GetLogger().Error("获取模板信息失败")
+		return
+	}
+
+	// 获取用户实名信息
+	var recordAuth models.Useresignrecord
+	has, err = db.GetEngine().Where("TEMPLATETYPE = 1 AND USERID = ?", userInfo.Userid).Get(&recordAuth)
+	if err != nil {
+		return
+	}
+	if !has {
+		err = errors.New("无对应实名认证记录信息")
+		logger.GetLogger().Error("无对应实名认证记录信息, userId:", userInfo.Userid)
+		return
+	}
+
+	// 调用爱签接口 - 上传待签署文件
+	contractNo := strconv.Itoa(int(utils.GenID()))
+	apiCreateContractReq := APICreateContractReq{
+		ContractNo:   contractNo,
+		ContractName: templateName,
+		SignOrder:    1,
+		ValidityTime: 30,
+		NotifyUrl:    config.SerCfg.AsignCfg.NotifyUrl,
+	}
+	apiCreateContractReq.Templates = []APITemplate{
+		{
+			TemplateNo: templateIdent,
+		},
+	}
+	apiCreateContractRsp, err := APICreateContract(apiCreateContractReq)
+	if err != nil {
+		return
+	}
+	if apiCreateContractRsp.Code != CODE_SUCCESS {
+		err = errors.New(apiCreateContractRsp.Msg)
+		return
+	}
+	// 将合同编号写入数据库
+	sql := fmt.Sprintf(`
+	UPDATE useresignrecord 
+	SET contractNo = '%v',
+		UPDATETIME = SYSDATE
+	WHERE RECORDID = %v
+	`, contractNo, record.RECORDID)
+	if _, err = db.GetEngine().Exec(sql); err != nil {
+		logger.GetLogger().Error("更新合同编号失败, err:", err)
+		err = errors.New("更新合同编号失败")
+		return
+	}
+
+	// 添加签署方 - 甲方 - 交易所
+	appAddSignerReq1 := APIAddSignerReq{
+		ContractNo: contractNo,
+		Account:    "ZR_LEGAL",
+		SignType:   2, // 无感知签约(需要开通权限)
+		SignStrategyList: []APISignStrategy{
+			{AttachNo: 1, LocationMode: 4, SignKey: "PARTYA_SIGNATURE", SignType: 1}, // 甲方签章
+			{AttachNo: 1, LocationMode: 4, SignKey: "PARTYA_DATE", SignType: 2},      // 甲方签署时间
+		},
+	}
+
+	// 获取临时存储的用户认证信息
+	cacheMap := make(map[string]interface{})
+	if err = json.Unmarshal([]byte(recordAuth.AUTHINFO), &cacheMap); err != nil {
+		logger.GetLogger().Error("反序列化临时存储用户信息失败, AUTHINFO:", recordAuth.AUTHINFO)
+		return
+	}
+	if recordAuth.AUTHINFO == "" {
+		err = errors.New("获取实名信息失败")
+		logger.GetLogger().Error("获取实名信息失败")
+		return
+	}
+
+	// 添加签署方 - 乙方 - 投资者
+	appAddSignerReq2 := APIAddSignerReq{
+		ContractNo:   contractNo,
+		Account:      strconv.Itoa(int(record.USERID)),
+		SignType:     3,
+		ValidateType: 3,
+	}
+	// 签章策略
+	signStrategyList := make([]APISignStrategy, 0)
+	// 接收方模板填充策略
+	receiverFillStrategyList := make([]APIReceiverFillStrategy, 0)
+	if userInfo.Userinfotype == 1 { // 个人
+		// 乙方签章
+		signStrategyList = append(signStrategyList, APISignStrategy{AttachNo: 1, LocationMode: 4, SignKey: "P_PARTYB_SIGNATURE", SignType: 1})
+		// 乙方签署时间
+		signStrategyList = append(signStrategyList, APISignStrategy{AttachNo: 1, LocationMode: 4, SignKey: "P_PARTYB_DATE", SignType: 2})
+
+		// 身份证号
+		receiverFillStrategyList = append(receiverFillStrategyList, APIReceiverFillStrategy{AttachNo: 1, Key: "P_PARTYB_ID", Value: cacheMap["idCardNo"].(string)})
+		// 联系方式
+		receiverFillStrategyList = append(receiverFillStrategyList, APIReceiverFillStrategy{AttachNo: 1, Key: "P_PARTYB_MOBILE", Value: cacheMap["mobile"].(string)})
+	} else { // 企业
+		// 乙方签章
+		signStrategyList = append(signStrategyList, APISignStrategy{AttachNo: 1, LocationMode: 4, SignKey: "E_PARTYB_SIGNATURE", SignType: 1})
+		// 乙方签署时间
+		signStrategyList = append(signStrategyList, APISignStrategy{AttachNo: 1, LocationMode: 4, SignKey: "E_PARTYB_DATE", SignType: 2})
+
+		// 法定代表人名称
+		receiverFillStrategyList = append(receiverFillStrategyList, APIReceiverFillStrategy{AttachNo: 1, Key: "E_PARTYB_LEGAL", Value: cacheMap["realName"].(string)})
+	}
+	appAddSignerReq2.SignStrategyList = signStrategyList
+	appAddSignerReq2.ReceiverFillStrategyList = receiverFillStrategyList
+	apiAddSignerRsp, err := APIAddSigner([]APIAddSignerReq{appAddSignerReq1, appAddSignerReq2})
+	if err != nil {
+		return
+	}
+	if apiAddSignerRsp.Code != CODE_SUCCESS {
+		err = errors.New(apiAddSignerRsp.Msg)
+		return
+	}
+	if len(apiAddSignerRsp.Data.SignUser) == 0 {
+		err = errors.New("获取合同签署地址失败")
+		logger.GetLogger().Error("获取合同签署地址失败")
+		return
+	}
+
+	// 将返回的合同签署地址写入数据库
+	sql = fmt.Sprintf(`
+				UPDATE useresignrecord 
+				SET RECORDSTATUS = 2, 
+					SIGNURL = '%v', 
+					UPDATETIME = SYSDATE
+				WHERE RECORDID = %v
+			`, apiAddSignerRsp.Data.SignUser[0].SignUrl, record.RECORDID)
+	if _, err = db.GetEngine().Exec(sql); err != nil {
+		logger.GetLogger().Error("合同签署地址失败, err:", err)
+		err = errors.New("合同签署地址失败")
+		return
+	}
+
+	rsp = CreateContractRsp{SignUrl: apiAddSignerRsp.Data.SignUser[0].SignUrl}
+
+	return
+}
+
+func ASignCompleted(contractNo, status string) (err error) {
+	/*
+		// 合同签署完成后回调通知示例
+		String publickey = "MFwwDQcccccxxxxmEz/nw27Ln6AP90ZCMPi+iNF1m9mhNECAwEAAQ==";
+		String remark = ""; // 若被拒签则会返回拒签原因,拒签原因不参与签名
+		Map <String, String> map = new HashMap<>();
+		map.put("action", "signCompleted");
+		map.put("contractNo", "20221114142140345");
+		map.put("status", "2");
+		map.put("signTime", "2022-11-14 14:22:00");
+		map.put("timestamp", "1668406920005");
+		map.put("validityTime", "2022-11-24 23:59:59");
+		String json = JSONObject.toJSONString(map, SerializerFeature.MapSortField);
+		System.out.println("数据:" + json);
+		// 计算签名
+		try {
+		String sign = "feFfcprGjdmDDqRmxK5qlWlMncX0mc6LJ5agebOGIx2QiAern+6ZRg/SBHOgvHp/+1ywVRdyKNUKxPneETwKPw==";
+		System.out.println(RSAUtils.rsaSignCheck(sign, json, publickey));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	*/
+
+	// 获取合同编号
+	if contractNo == "" {
+		logger.GetLogger().Error("获取合同编号失败")
+		err = errors.New("获取合同编号失败")
+		return
+	}
+	// 获取合同状态
+	if status == "" {
+		logger.GetLogger().Error("获取获取合同状态失败")
+		err = errors.New("获取获取合同状态失败")
+		return
+	}
+
+	// 更新数据库记录
+	sql := fmt.Sprintf(`
+				UPDATE useresignrecord
+				SET RECORDSTATUS = 3,
+					UPDATETIME = SYSDATE
+				WHERE CONTRACTNO = '%v'  
+			`, contractNo)
+	_, err = db.GetEngine().Exec(sql)
 
 	return
 }

BIN
services/asign/templates/中融/客户交易须知-个人.doc


BIN
services/asign/templates/中融/客户交易须知-企业.doc


+ 94 - 0
services/asign/test/main.go

@@ -0,0 +1,94 @@
+package main
+
+import (
+	"fmt"
+	"mtp2_if/utils"
+	"reflect"
+	"sort"
+
+	"github.com/fatih/structs"
+)
+
+type aPIAAA struct {
+	Account         string   `json:"account" binding:"required"`            // 用户唯一识别码(请转入UserID)
+	SerialNo        string   `json:"serialNo"`                              // 实名认证流水号
+	Name            *string  `json:"name" structs:",omitempty"`             // 用户姓名
+	IdCard          string   `json:"idCard"  structs:",omitempty"`          // 个人身份证、台胞证、港澳通行证等证件号
+	IdCardType      *int     `json:"idCardType" structs:",omitempty"`       // 证件类型 1:居民身份证 2:台湾居民来往内地通行证 3:港澳居民往来内地通行证 10:武装警察身份证 11:军人身份证 15:警察(警官)证 21:外国人永久居留证 23:护照
+	Mobile          string   `json:"mobile"  structs:",omitempty"`          // 手机号码
+	SignPwd         string   `json:"signPwd"  structs:",omitempty"`         // 签约密码(MTP2登录密码加密方式),如果为空将随机生成签约密码(当签约方式为“签约密码签约”时会使用到,可通过重置接口修改)
+	IsSignPwdNotice *float64 `json:"isSignPwdNotice"  structs:",omitempty"` // 是否将签约密码以短信形式通知用户 0:不通知(默认) 1:通知
+	IsNotice        *bool    `json:"isNotice"  structs:",omitempty"`        // 用户发起合同或需要签署时是否进行短信通知 0:否(默认) 1:是
+}
+
+func main() {
+	req := &aPIAAA{
+		Account: "1111",
+	}
+	req.SerialNo = "2222"
+	req.Name = utils.SetPointValue("")
+	req.IdCardType = utils.SetPointValue(1)
+	req.IsSignPwdNotice = utils.SetPointValue(5.01)
+	reqMap := structs.Map(req)
+
+	aaa := sortMapByKey(reqMap)
+
+	fmt.Println(aaa)
+}
+
+func sortMapByKey(data map[string]interface{}) (sortedData string) {
+	keys := make([]string, 0, len(data))
+	for k := range data {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for i, k := range keys {
+		if i > 0 {
+			sortedData += ","
+		}
+
+		// 判断是否指针
+		v := reflect.ValueOf(data[k])
+		if v.Kind() == reflect.Ptr {
+			switch data[k].(type) {
+			case *string:
+				sortedData += fmt.Sprintf(`"%s":"%s"`, k, *(data[k].(*string)))
+			case *map[string]interface{}:
+				sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(*(data[k].(*map[string]interface{}))))
+			case *[]interface{}:
+				list := data[k].([]interface{})
+				sortedData += fmt.Sprintf(`"%s":[`, k)
+				for j, item := range list {
+					if j > 0 {
+						sortedData += ","
+					}
+					sortedData += sortMapByKey(item.(map[string]interface{}))
+				}
+				sortedData += "]"
+			default:
+				sortedData += fmt.Sprintf(`"%s":%v`, k, reflect.ValueOf(data[k]).Elem())
+			}
+		} else {
+			switch data[k].(type) {
+			case string:
+				sortedData += fmt.Sprintf(`"%s":"%s"`, k, data[k].(string))
+			case map[string]interface{}:
+				sortedData += fmt.Sprintf(`"%s":%s`, k, sortMapByKey(data[k].(map[string]interface{})))
+			case []interface{}:
+				list := data[k].([]interface{})
+				sortedData += fmt.Sprintf(`"%s":[`, k)
+				for j, item := range list {
+					if j > 0 {
+						sortedData += ","
+					}
+					sortedData += sortMapByKey(item.(map[string]interface{}))
+				}
+				sortedData += "]"
+			default:
+				sortedData += fmt.Sprintf(`"%s":%v`, k, data[k])
+			}
+		}
+	}
+
+	return fmt.Sprintf("{%s}", sortedData)
+}

+ 21 - 0
utils/snowflake.go

@@ -0,0 +1,21 @@
+package utils
+
+import (
+	"time"
+
+	"github.com/bwmarrin/snowflake"
+)
+
+var node *snowflake.Node
+
+func InitSnowflake(st time.Time, machineID int64) (err error) {
+	snowflake.Epoch = st.UnixNano() / 1e6
+	node, err = snowflake.NewNode(machineID)
+
+	return
+}
+
+// 生成 64 位的 雪花 ID
+func GenID() int64 {
+	return node.Generate().Int64()
+}