This commit is contained in:
2025-07-20 20:53:26 +08:00
parent 83bf9aea7d
commit 8ad1d7288e
158 changed files with 18156 additions and 13188 deletions

View File

@@ -0,0 +1,293 @@
# e签宝 SDK - 重构版本
这是重构后的e签宝Go SDK提供了更清晰、更易用的API接口。
## 架构设计
### 主要组件
1. **Client (client.go)** - 统一的客户端入口
2. **Config (config.go)** - 配置管理
3. **HTTPClient (http.go)** - HTTP请求处理
4. **服务模块**
- **TemplateService** - 模板操作服务
- **SignFlowService** - 签署流程服务
- **OrgAuthService** - 机构认证服务
- **FileOpsService** - 文件操作服务
### 设计特点
-**模块化设计**:功能按模块分离,职责清晰
-**统一入口**通过Client提供统一的API
-**易于使用**:提供高级业务接口和底层操作接口
-**配置管理**:集中的配置验证和管理
-**错误处理**:统一的错误处理和响应验证
-**类型安全**:完整的类型定义和结构体
## 快速开始
### 1. 创建客户端
```go
package main
import (
"github.com/your-org/tyapi-server-gin/internal/shared/esign"
)
func main() {
// 创建配置
config, err := esign.NewConfig(
"your_app_id",
"your_app_secret",
"https://smlopenapi.esign.cn",
"your_template_id",
)
if err != nil {
panic(err)
}
// 创建客户端
client := esign.NewClient(config)
}
```
### 2. 基础用法 - 一键合同签署
```go
// 最简单的合同签署
result, err := client.GenerateContractSigning(&esign.ContractSigningRequest{
CompanyName: "我的公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
LegalPersonPhone: "13800138000",
})
if err != nil {
log.Fatal("签署失败:", err)
}
fmt.Printf("请访问链接进行签署: %s\n", result.SignURL)
```
### 3. 企业认证
```go
// 企业认证
authResult, err := client.GenerateEnterpriseAuth(&esign.EnterpriseAuthRequest{
CompanyName: "我的公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
TransactorName: "李四",
TransactorPhone: "13800138001",
TransactorID: "123456789012345679",
})
if err != nil {
log.Fatal("企业认证失败:", err)
}
fmt.Printf("请访问链接进行企业认证: %s\n", authResult.AuthURL)
```
## 高级用法
### 分步操作
如果需要更精细的控制,可以使用分步操作:
```go
// 1. 填写模板
templateData := map[string]string{
"JFQY": "甲方公司",
"JFFR": "甲方法人",
"YFQY": "乙方公司",
"YFFR": "乙方法人",
"QDRQ": "2024年01月01日",
}
fileID, err := client.FillTemplate(templateData)
if err != nil {
return err
}
// 2. 创建签署流程
signFlowReq := &esign.CreateSignFlowRequest{
FileID: fileID,
SignerAccount: "123456789012345678",
SignerName: "乙方公司",
TransactorPhone: "13800138000",
TransactorName: "乙方法人",
TransactorIDCardNum: "123456789012345678",
TransactorMobile: "13800138000",
}
signFlowID, err := client.CreateSignFlow(signFlowReq)
if err != nil {
return err
}
// 3. 获取签署链接
signURL, shortURL, err := client.GetSignURL(signFlowID, "13800138000", "乙方公司")
if err != nil {
return err
}
// 4. 查询签署状态
status, err := client.GetSignFlowStatus(signFlowID)
if err != nil {
return err
}
// 5. 检查是否完成
completed, err := client.IsSignFlowCompleted(signFlowID)
if err != nil {
return err
}
```
### 自定义模板数据
```go
customData := map[string]string{
"custom_field_1": "自定义值1",
"custom_field_2": "自定义值2",
"contract_date": "2024年01月01日",
}
result, err := client.GenerateContractSigning(&esign.ContractSigningRequest{
CompanyName: "我的公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
LegalPersonPhone: "13800138000",
CustomData: customData, // 使用自定义数据
})
```
## API参考
### 主要接口
#### 合同签署
- `GenerateContractSigning(req *ContractSigningRequest) (*ContractSigningResult, error)` - 一键生成合同签署
#### 企业认证
- `GenerateEnterpriseAuth(req *EnterpriseAuthRequest) (*EnterpriseAuthResult, error)` - 一键企业认证
#### 模板操作
- `FillTemplate(components map[string]string) (string, error)` - 填写模板
- `FillTemplateWithDefaults(partyA, legalRepA, partyB, legalRepB string) (string, error)` - 使用默认数据填写模板
#### 签署流程
- `CreateSignFlow(req *CreateSignFlowRequest) (string, error)` - 创建签署流程
- `GetSignURL(signFlowID, psnAccount, orgName string) (string, string, error)` - 获取签署链接
- `QuerySignFlowDetail(signFlowID string) (*QuerySignFlowDetailResponse, error)` - 查询流程详情
- `IsSignFlowCompleted(signFlowID string) (bool, error)` - 检查是否完成
#### 机构认证
- `GetOrgAuthURL(req *OrgAuthRequest) (string, string, string, error)` - 获取认证链接
- `ValidateOrgAuthInfo(req *OrgAuthRequest) error` - 验证认证信息
#### 文件操作
- `DownloadSignedFile(signFlowID string) (*DownloadSignedFileResponse, error)` - 下载已签署文件
- `GetSignFlowStatus(signFlowID string) (string, error)` - 获取流程状态
## 配置管理
### 配置结构
```go
type Config struct {
AppID string `json:"app_id"` // 应用ID
AppSecret string `json:"app_secret"` // 应用密钥
ServerURL string `json:"server_url"` // 服务器URL
TemplateID string `json:"template_id"` // 模板ID
}
```
### 配置验证
SDK会自动验证配置的完整性
```go
config, err := esign.NewConfig("", "", "", "")
// 返回错误应用ID不能为空
// 手动验证
err := config.Validate()
```
## 错误处理
SDK提供统一的错误处理
```go
result, err := client.GenerateContractSigning(req)
if err != nil {
// 错误包含详细的错误信息
log.Printf("签署失败: %v", err)
return
}
```
## 迁移指南
### 从旧版本迁移
旧版本:
```go
service := service.NewEQService(config)
result, err := service.ExecuteSignProcess(req)
```
新版本:
```go
client := esign.NewClient(config)
result, err := client.GenerateContractSigning(req)
```
### 主要变化
1. **包名变更**`service``esign`
2. **入口简化**`EQService``Client`
3. **方法重命名**:更语义化的方法名
4. **结构重组**:按功能模块划分
5. **类型优化**:更简洁的请求/响应结构
## 示例代码
完整的示例代码请参考 `example.go` 文件。
## 注意事项
1. **配置安全**请妥善保管AppID和AppSecret
2. **网络超时**默认HTTP超时为30秒
3. **并发安全**Client实例是并发安全的
4. **错误重试**:建议实现适当的重试机制
5. **日志记录**SDK会输出调试信息生产环境请注意日志级别
## 常见问题
### Q: 如何更新配置?
```go
newConfig, _ := esign.NewConfig("new_app_id", "new_secret", "new_url", "new_template")
client.UpdateConfig(newConfig)
```
### Q: 如何处理网络错误?
```go
result, err := client.GenerateContractSigning(req)
if err != nil {
if strings.Contains(err.Error(), "timeout") {
// 处理超时
} else if strings.Contains(err.Error(), "API调用失败") {
// 处理API错误
}
}
```
### Q: 如何自定义HTTP客户端
当前版本使用内置的HTTP客户端如需自定义可以修改`http.go`中的客户端配置。

View File

@@ -0,0 +1,269 @@
package esign
import (
"fmt"
)
// Client e签宝客户端
// 提供统一的e签宝服务接口整合所有功能模块
type Client struct {
config *Config // 配置信息
httpClient *HTTPClient // HTTP客户端
template *TemplateService // 模板服务
signFlow *SignFlowService // 签署流程服务
orgAuth *OrgAuthService // 机构认证服务
fileOps *FileOpsService // 文件操作服务
}
// NewClient 创建e签宝客户端
// 使用配置信息初始化客户端及所有服务模块
//
// 参数:
// - config: e签宝配置信息
//
// 返回: 客户端实例
func NewClient(config *Config) *Client {
httpClient := NewHTTPClient(config)
client := &Client{
config: config,
httpClient: httpClient,
}
// 初始化各个服务模块
client.template = NewTemplateService(httpClient, config)
client.signFlow = NewSignFlowService(httpClient, config)
client.orgAuth = NewOrgAuthService(httpClient, config)
client.fileOps = NewFileOpsService(httpClient, config)
return client
}
// GetConfig 获取当前配置
func (c *Client) GetConfig() *Config {
return c.config
}
// UpdateConfig 更新配置
func (c *Client) UpdateConfig(config *Config) {
c.config = config
c.httpClient.UpdateConfig(config)
// 更新各服务模块的配置
c.template.UpdateConfig(config)
c.signFlow.UpdateConfig(config)
c.orgAuth.UpdateConfig(config)
c.fileOps.UpdateConfig(config)
}
// ==================== 模板操作 ====================
// FillTemplate 填写模板
// 使用自定义数据填写模板生成文件
func (c *Client) FillTemplate(components map[string]string) (*FillTemplate, error) {
return c.template.FillWithCustomData(components)
}
// FillTemplateWithDefaults 使用默认数据填写模板
func (c *Client) FillTemplateWithDefaults(partyA, legalRepA, partyB, legalRepB string) (*FillTemplate, error) {
return c.template.FillWithDefaults(partyA, legalRepA, partyB, legalRepB)
}
// ==================== 签署流程 ====================
// CreateSignFlow 创建签署流程
func (c *Client) CreateSignFlow(req *CreateSignFlowRequest) (string, error) {
return c.signFlow.Create(req)
}
// GetSignURL 获取签署链接
func (c *Client) GetSignURL(signFlowID, psnAccount, orgName string) (string, string, error) {
return c.signFlow.GetSignURL(signFlowID, psnAccount, orgName)
}
// QuerySignFlowDetail 查询签署流程详情
func (c *Client) QuerySignFlowDetail(signFlowID string) (*QuerySignFlowDetailResponse, error) {
return c.fileOps.QuerySignFlowDetail(signFlowID)
}
// IsSignFlowCompleted 检查签署流程是否完成
func (c *Client) IsSignFlowCompleted(signFlowID string) (bool, error) {
result, err := c.QuerySignFlowDetail(signFlowID)
if err != nil {
return false, err
}
// 状态码2表示已完成
return result.Data.SignFlowStatus == 2, nil
}
// ==================== 机构认证 ====================
// GetOrgAuthURL 获取机构认证链接
func (c *Client) GetOrgAuthURL(req *OrgAuthRequest) (string, string, string, error) {
return c.orgAuth.GetAuthURL(req)
}
// ValidateOrgAuthInfo 验证机构认证信息
func (c *Client) ValidateOrgAuthInfo(req *OrgAuthRequest) error {
return c.orgAuth.ValidateAuthInfo(req)
}
// ==================== 文件操作 ====================
// DownloadSignedFile 下载已签署文件
func (c *Client) DownloadSignedFile(signFlowID string) (*DownloadSignedFileResponse, error) {
return c.fileOps.DownloadSignedFile(signFlowID)
}
// GetSignFlowStatus 获取签署流程状态
func (c *Client) GetSignFlowStatus(signFlowID string) (string, error) {
detail, err := c.QuerySignFlowDetail(signFlowID)
if err != nil {
return "", err
}
return GetSignFlowStatusText(detail.Data.SignFlowStatus), nil
}
// ==================== 业务集成接口 ====================
// ContractSigningRequest 合同签署请求
type ContractSigningRequest struct {
// 企业信息
CompanyName string `json:"companyName"` // 企业名称
UnifiedSocialCode string `json:"unifiedSocialCode"` // 统一社会信用代码
LegalPersonName string `json:"legalPersonName"` // 法人姓名
LegalPersonID string `json:"legalPersonId"` // 法人身份证号
LegalPersonPhone string `json:"legalPersonPhone"` // 法人手机号
// 经办人信息(可选,如果与法人不同)
TransactorName string `json:"transactorName,omitempty"` // 经办人姓名
TransactorPhone string `json:"transactorPhone,omitempty"` // 经办人手机号
TransactorID string `json:"transactorId,omitempty"` // 经办人身份证号
// 模板数据(可选)
CustomData map[string]string `json:"customData,omitempty"` // 自定义模板数据
}
// ContractSigningResult 合同签署结果
type ContractSigningResult struct {
FileID string `json:"fileId"` // 文件ID
SignFlowID string `json:"signFlowId"` // 签署流程ID
SignURL string `json:"signUrl"` // 签署链接
ShortURL string `json:"shortUrl"` // 短链接
}
// GenerateContractSigning 生成合同签署
// 一站式合同签署服务:填写模板 -> 创建签署流程 -> 获取签署链接
func (c *Client) GenerateContractSigning(req *ContractSigningRequest) (*ContractSigningResult, error) {
// 1. 准备模板数据
var err error
var fillTemplate *FillTemplate
if len(req.CustomData) > 0 {
// 使用自定义数据
fillTemplate, err = c.FillTemplate(req.CustomData)
} else {
// 使用默认数据
fillTemplate, err = c.FillTemplateWithDefaults(
"海南省学宇思网络科技有限公司",
"刘福思",
req.CompanyName,
req.LegalPersonName,
)
}
if err != nil {
return nil, fmt.Errorf("填写模板失败: %w", err)
}
// 2. 确定签署人信息
signerName := req.LegalPersonName
transactorName := req.LegalPersonName
transactorPhone := req.LegalPersonPhone
transactorID := req.LegalPersonID
if req.TransactorName != "" {
signerName = req.TransactorName
transactorName = req.TransactorName
transactorPhone = req.TransactorPhone
transactorID = req.TransactorID
}
// 3. 创建签署流程
signFlowReq := &CreateSignFlowRequest{
FileID: fillTemplate.FileID,
SignerAccount: req.UnifiedSocialCode,
SignerName: signerName,
TransactorPhone: transactorPhone,
TransactorName: transactorName,
TransactorIDCardNum: transactorID,
}
signFlowID, err := c.CreateSignFlow(signFlowReq)
if err != nil {
return nil, fmt.Errorf("创建签署流程失败: %w", err)
}
// 4. 获取签署链接
signURL, shortURL, err := c.GetSignURL(signFlowID, transactorPhone, signerName)
if err != nil {
return nil, fmt.Errorf("获取签署链接失败: %w", err)
}
return &ContractSigningResult{
FileID: fillTemplate.FileID,
SignFlowID: signFlowID,
SignURL: signURL,
ShortURL: shortURL,
}, nil
}
// EnterpriseAuthRequest 企业认证请求
type EnterpriseAuthRequest struct {
// 企业信息
CompanyName string `json:"companyName"` // 企业名称
UnifiedSocialCode string `json:"unifiedSocialCode"` // 统一社会信用代码
LegalPersonName string `json:"legalPersonName"` // 法人姓名
LegalPersonID string `json:"legalPersonId"` // 法人身份证号
// 经办人信息
TransactorName string `json:"transactorName"` // 经办人姓名
TransactorMobile string `json:"transactorMobile"` // 经办人手机号
TransactorID string `json:"transactorId"` // 经办人身份证号
}
// EnterpriseAuthResult 企业认证结果
type EnterpriseAuthResult struct {
AuthFlowID string `json:"authFlowId"` // 认证流程ID
AuthURL string `json:"authUrl"` // 认证链接
AuthShortURL string `json:"authShortUrl"` // 短链接
}
// GenerateEnterpriseAuth 生成企业认证
// 一站式企业认证服务
func (c *Client) GenerateEnterpriseAuth(req *EnterpriseAuthRequest) (*EnterpriseAuthResult, error) {
authReq := &OrgAuthRequest{
OrgName: req.CompanyName,
OrgIDCardNum: req.UnifiedSocialCode,
LegalRepName: req.LegalPersonName,
LegalRepIDCardNum: req.LegalPersonID,
TransactorName: req.TransactorName,
TransactorIDCardNum: req.TransactorID,
TransactorMobile: req.TransactorMobile,
}
// 验证信息
if err := c.ValidateOrgAuthInfo(authReq); err != nil {
return nil, fmt.Errorf("认证信息验证失败: %w", err)
}
// 获取认证链接
authFlowID, authURL, shortURL, err := c.GetOrgAuthURL(authReq)
if err != nil {
return nil, fmt.Errorf("获取认证链接失败: %w", err)
}
return &EnterpriseAuthResult{
AuthFlowID: authFlowID,
AuthURL: authURL,
AuthShortURL: shortURL,
}, nil
}

View File

@@ -0,0 +1,83 @@
package esign
import "fmt"
// Config e签宝服务配置结构体
// 包含应用ID、密钥、服务器URL和模板ID等基础配置信息
type Config struct {
AppID string `json:"appId"` // 应用ID
AppSecret string `json:"appSecret"` // 应用密钥
ServerURL string `json:"serverUrl"` // 服务器URL
TemplateID string `json:"templateId"` // 模板ID
}
// NewConfig 创建新的配置实例
// 提供配置验证和默认值设置
func NewConfig(appID, appSecret, serverURL, templateID string) (*Config, error) {
if appID == "" {
return nil, fmt.Errorf("应用ID不能为空")
}
if appSecret == "" {
return nil, fmt.Errorf("应用密钥不能为空")
}
if serverURL == "" {
return nil, fmt.Errorf("服务器URL不能为空")
}
if templateID == "" {
return nil, fmt.Errorf("模板ID不能为空")
}
return &Config{
AppID: appID,
AppSecret: appSecret,
ServerURL: serverURL,
TemplateID: templateID,
}, nil
}
// Validate 验证配置的完整性
func (c *Config) Validate() error {
if c.AppID == "" {
return fmt.Errorf("应用ID不能为空")
}
if c.AppSecret == "" {
return fmt.Errorf("应用密钥不能为空")
}
if c.ServerURL == "" {
return fmt.Errorf("服务器URL不能为空")
}
if c.TemplateID == "" {
return fmt.Errorf("模板ID不能为空")
}
return nil
}
// 认证模式常量
const (
// 个人认证模式
AuthModeMobile3 = "PSN_MOBILE3" // 手机号三要素认证
AuthModeIDCard = "PSN_IDCARD" // 身份证认证
AuthModeBank = "PSN_BANK" // 银行卡认证
// 意愿认证模式
WillingnessAuthSMS = "CODE_SMS" // 短信验证码
WillingnessAuthEmail = "CODE_EMAIL" // 邮箱验证码
// 证件类型常量
IDCardTypeChina = "CRED_PSN_CH_IDCARD" // 中国大陆居民身份证
OrgCardTypeUSCC = "CRED_ORG_USCC" // 统一社会信用代码
// 签署区样式常量
SignFieldStyleNormal = 1 // 普通签章
SignFieldStyleSeam = 2 // 骑缝签章
// 签署人类型常量
SignerTypePerson = 0 // 个人
SignerTypeOrg = 1 // 机构
// URL类型常量
UrlTypeSign = 2 // 签署链接
// 客户端类型常量
ClientTypeAll = "ALL" // 所有客户端
)

View File

@@ -0,0 +1,193 @@
package esign
import (
"fmt"
"log"
)
// Example 展示如何使用重构后的e签宝SDK
func Example() {
// 1. 创建配置
config, err := NewConfig(
"your_app_id",
"your_app_secret",
"https://smlopenapi.esign.cn",
"your_template_id",
)
if err != nil {
log.Fatal("配置创建失败:", err)
}
// 2. 创建客户端
client := NewClient(config)
// 示例1: 简单合同签署流程
fmt.Println("=== 示例1: 简单合同签署流程 ===")
contractReq := &ContractSigningRequest{
CompanyName: "测试公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
LegalPersonPhone: "13800138000",
}
result, err := client.GenerateContractSigning(contractReq)
if err != nil {
log.Printf("合同签署失败: %v", err)
} else {
fmt.Printf("合同签署成功: %+v\n", result)
}
// 示例2: 企业认证流程
fmt.Println("\n=== 示例2: 企业认证流程 ===")
authReq := &EnterpriseAuthRequest{
CompanyName: "测试公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
TransactorName: "李四",
TransactorMobile: "13800138001",
TransactorID: "123456789012345679",
}
authResult, err := client.GenerateEnterpriseAuth(authReq)
if err != nil {
log.Printf("企业认证失败: %v", err)
} else {
fmt.Printf("企业认证成功: %+v\n", authResult)
}
// 示例3: 分步操作
fmt.Println("\n=== 示例3: 分步操作 ===")
// 3.1 填写模板
templateData := map[string]string{
"JFQY": "甲方公司",
"JFFR": "甲方法人",
"YFQY": "乙方公司",
"YFFR": "乙方法人",
"QDRQ": "2024年01月01日",
}
fileID, err := client.FillTemplate(templateData)
if err != nil {
log.Printf("模板填写失败: %v", err)
return
}
fmt.Printf("模板填写成功文件ID: %s\n", fileID)
// 3.2 创建签署流程
signFlowReq := &CreateSignFlowRequest{
FileID: fileID.FileID,
SignerAccount: "123456789012345678",
SignerName: "乙方公司",
TransactorPhone: "13800138000",
TransactorName: "乙方法人",
TransactorIDCardNum: "123456789012345678",
}
signFlowID, err := client.CreateSignFlow(signFlowReq)
if err != nil {
log.Printf("创建签署流程失败: %v", err)
return
}
fmt.Printf("签署流程创建成功流程ID: %s\n", signFlowID)
// 3.3 获取签署链接
signURL, shortURL, err := client.GetSignURL(signFlowID, "13800138000", "乙方公司")
if err != nil {
log.Printf("获取签署链接失败: %v", err)
return
}
fmt.Printf("签署链接: %s\n", signURL)
fmt.Printf("短链接: %s\n", shortURL)
// 3.4 查询签署状态
status, err := client.GetSignFlowStatus(signFlowID)
if err != nil {
log.Printf("查询签署状态失败: %v", err)
return
}
fmt.Printf("签署状态: %s\n", status)
// 3.5 检查是否完成
completed, err := client.IsSignFlowCompleted(signFlowID)
if err != nil {
log.Printf("检查签署状态失败: %v", err)
return
}
fmt.Printf("签署是否完成: %t\n", completed)
}
// ExampleBasicUsage 基础用法示例
func ExampleBasicUsage() {
// 最简单的用法 - 一行代码完成合同签署
config, _ := NewConfig("app_id", "app_secret", "server_url", "template_id")
client := NewClient(config)
// 快速合同签署
result, err := client.GenerateContractSigning(&ContractSigningRequest{
CompanyName: "我的公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
LegalPersonPhone: "13800138000",
})
if err != nil {
log.Fatal("签署失败:", err)
}
fmt.Printf("请访问以下链接进行签署: %s\n", result.SignURL)
}
// ExampleWithCustomData 自定义数据示例
func ExampleWithCustomData() {
config, _ := NewConfig("app_id", "app_secret", "server_url", "template_id")
client := NewClient(config)
// 使用自定义模板数据
customData := map[string]string{
"custom_field_1": "自定义值1",
"custom_field_2": "自定义值2",
"contract_date": "2024年01月01日",
}
result, err := client.GenerateContractSigning(&ContractSigningRequest{
CompanyName: "我的公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
LegalPersonPhone: "13800138000",
CustomData: customData,
})
if err != nil {
log.Fatal("签署失败:", err)
}
fmt.Printf("自定义合同签署链接: %s\n", result.SignURL)
}
// ExampleEnterpriseAuth 企业认证示例
func ExampleEnterpriseAuth() {
config, _ := NewConfig("app_id", "app_secret", "server_url", "template_id")
client := NewClient(config)
// 企业认证
authResult, err := client.GenerateEnterpriseAuth(&EnterpriseAuthRequest{
CompanyName: "我的公司",
UnifiedSocialCode: "123456789012345678",
LegalPersonName: "张三",
LegalPersonID: "123456789012345678",
TransactorName: "李四",
TransactorMobile: "13800138001",
TransactorID: "123456789012345679",
})
if err != nil {
log.Fatal("企业认证失败:", err)
}
fmt.Printf("请访问以下链接进行企业认证: %s\n", authResult.AuthURL)
}

View File

@@ -0,0 +1,208 @@
package esign
import (
"fmt"
)
// FileOpsService 文件操作服务
// 处理文件下载、流程查询等操作
type FileOpsService struct {
httpClient *HTTPClient
config *Config
}
// NewFileOpsService 创建文件操作服务
func NewFileOpsService(httpClient *HTTPClient, config *Config) *FileOpsService {
return &FileOpsService{
httpClient: httpClient,
config: config,
}
}
// UpdateConfig 更新配置
func (s *FileOpsService) UpdateConfig(config *Config) {
s.config = config
}
// DownloadSignedFile 下载已签署文件及附属材料
// 获取签署完成后的文件下载链接和证书下载链接
//
// 参数说明:
// - signFlowId: 签署流程ID
//
// 返回: 下载文件响应和错误信息
func (s *FileOpsService) DownloadSignedFile(signFlowId string) (*DownloadSignedFileResponse, error) {
fmt.Println("开始下载已签署文件及附属材料...")
// 发送API请求
urlPath := fmt.Sprintf("/v3/sign-flow/%s/attachments", signFlowId)
responseBody, err := s.httpClient.Request("GET", urlPath, nil)
if err != nil {
return nil, fmt.Errorf("下载已签署文件失败: %v", err)
}
// 解析响应
var response DownloadSignedFileResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return nil, err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return nil, err
}
fmt.Printf("已签署文件下载信息获取成功!\n")
fmt.Printf("文件数量: %d\n", len(response.Data.Files))
fmt.Printf("附属材料数量: %d\n", len(response.Data.Attachments))
if response.Data.CertificateDownloadUrl != "" {
fmt.Printf("证书下载链接: %s\n", response.Data.CertificateDownloadUrl)
}
return &response, nil
}
// QuerySignFlowDetail 查询签署流程详情
// 获取签署流程的详细状态和参与方信息
//
// 参数说明:
// - signFlowId: 签署流程ID
//
// 返回: 流程详情响应和错误信息
func (s *FileOpsService) QuerySignFlowDetail(signFlowId string) (*QuerySignFlowDetailResponse, error) {
fmt.Println("开始查询签署流程详情...")
// 发送API请求
urlPath := fmt.Sprintf("/v3/sign-flow/%s/detail", signFlowId)
responseBody, err := s.httpClient.Request("GET", urlPath, nil)
if err != nil {
return nil, fmt.Errorf("查询签署流程详情失败: %v", err)
}
// 解析响应
var response QuerySignFlowDetailResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return nil, err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return nil, err
}
fmt.Printf("查询签署流程详情响应: %+v\n", response)
return &response, nil
}
// GetSignedFileDownloadUrls 获取已签署文件的下载链接
// 从下载响应中提取所有文件的下载链接
//
// 参数说明:
// - downloadResponse: 下载文件响应
//
// 返回: 文件下载链接映射
func GetSignedFileDownloadUrls(downloadResponse *DownloadSignedFileResponse) map[string]string {
urls := make(map[string]string)
// 添加已签署文件
for _, file := range downloadResponse.Data.Files {
urls[file.FileName] = file.DownloadUrl
}
// 添加附属材料
for _, attachment := range downloadResponse.Data.Attachments {
urls[attachment.FileName] = attachment.DownloadUrl
}
return urls
}
// GetSignFlowStatusText 获取签署流程状态文本
// 从流程详情中提取状态信息
//
// 参数说明:
// - status: 流程状态码
//
// 返回: 流程状态描述
func GetSignFlowStatusText(status int32) string {
switch status {
case 1:
return "草稿"
case 2:
return "签署中"
case 3:
return "已完成"
case 4:
return "已撤销"
case 5:
return "已过期"
case 6:
return "已拒绝"
default:
return fmt.Sprintf("未知状态(%d)", status)
}
}
// GetSignerStatus 获取签署人状态
// 从流程详情中提取指定签署人的状态
//
// 参数说明:
// - detailResponse: 流程详情响应
// - signerName: 签署人姓名
//
// 返回: 签署人状态描述
func GetSignerStatus(detailResponse *QuerySignFlowDetailResponse, signerName string) string {
for _, signer := range detailResponse.Data.Signers {
var name string
if signer.PsnSigner != nil {
name = signer.PsnSigner.PsnName
} else if signer.OrgSigner != nil {
name = signer.OrgSigner.OrgName
}
if name == signerName {
switch signer.SignStatus {
case 1:
return "待签署"
case 2:
return "已签署"
case 3:
return "已拒绝"
case 4:
return "已过期"
default:
return fmt.Sprintf("未知状态(%d)", signer.SignStatus)
}
}
}
return "未找到签署人"
}
// IsSignFlowCompleted 检查签署流程是否完成
// 根据状态码判断签署流程是否已完成
//
// 参数说明:
// - detailResponse: 流程详情响应
//
// 返回: 是否完成
func IsSignFlowCompleted(detailResponse *QuerySignFlowDetailResponse) bool {
// 状态码2表示已完成
return detailResponse.Data.SignFlowStatus == 2
}
// GetFileList 获取文件列表
// 从下载响应中获取所有文件信息
//
// 参数说明:
// - downloadResponse: 下载文件响应
//
// 返回: 文件信息列表
func GetFileList(downloadResponse *DownloadSignedFileResponse) []SignedFileInfo {
var files []SignedFileInfo
// 添加已签署文件
files = append(files, downloadResponse.Data.Files...)
// 添加附属材料
files = append(files, downloadResponse.Data.Attachments...)
return files
}

View File

@@ -0,0 +1,199 @@
package esign
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
// HTTPClient e签宝HTTP客户端
// 处理所有e签宝API的HTTP请求包括签名生成、请求头设置等
type HTTPClient struct {
config *Config
client *http.Client
}
// NewHTTPClient 创建HTTP客户端
func NewHTTPClient(config *Config) *HTTPClient {
return &HTTPClient{
config: config,
client: &http.Client{Timeout: 30 * time.Second},
}
}
// UpdateConfig 更新配置
func (h *HTTPClient) UpdateConfig(config *Config) {
h.config = config
}
// Request e签宝通用请求函数
// 处理所有e签宝API的HTTP请求包括签名生成、请求头设置等
//
// 参数说明:
// - method: HTTP方法GET、POST等
// - urlPath: API路径
// - body: 请求体字节数组
//
// 返回: 响应体字节数组和错误信息
func (h *HTTPClient) Request(method, urlPath string, body []byte) ([]byte, error) {
// 生成签名所需参数
timestamp := getCurrentTimestamp()
nonce := generateNonce()
date := getCurrentDate()
// 计算Content-MD5
contentMD5 := ""
if len(body) > 0 {
contentMD5 = getContentMD5(body)
}
// 根据Java示例Headers为空字符串
headers := ""
// 生成签名
signature := generateSignature(h.config.AppSecret, method, "*/*", contentMD5, "application/json", date, headers, urlPath)
// 创建HTTP请求
url := h.config.ServerURL + urlPath
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
if err != nil {
return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-MD5", contentMD5)
req.Header.Set("Date", date)
req.Header.Set("Accept", "*/*")
req.Header.Set("X-Tsign-Open-App-Id", h.config.AppID)
req.Header.Set("X-Tsign-Open-Auth-Mode", "Signature")
req.Header.Set("X-Tsign-Open-Ca-Timestamp", timestamp)
req.Header.Set("X-Tsign-Open-Nonce", nonce)
req.Header.Set("X-Tsign-Open-Ca-Signature", signature)
// 发送请求
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
}
defer resp.Body.Close()
// 读取响应
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %v", err)
}
// 打印响应内容用于调试
fmt.Printf("API响应状态码: %d\n", resp.StatusCode)
fmt.Printf("API响应内容: %s\n", string(responseBody))
// 检查响应状态码
if resp.StatusCode != 200 {
return nil, fmt.Errorf("API请求失败状态码: %d", resp.StatusCode)
}
return responseBody, nil
}
// MarshalRequest 序列化请求数据为JSON
//
// 参数:
// - data: 要序列化的数据
//
// 返回: JSON字节数组和错误信息
func MarshalRequest(data interface{}) ([]byte, error) {
jsonData, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("序列化请求数据失败: %v", err)
}
return jsonData, nil
}
// UnmarshalResponse 反序列化响应数据
//
// 参数:
// - responseBody: 响应体字节数组
// - response: 目标响应结构体指针
//
// 返回: 错误信息
func UnmarshalResponse(responseBody []byte, response interface{}) error {
if err := json.Unmarshal(responseBody, response); err != nil {
return fmt.Errorf("解析响应失败: %v响应内容: %s", err, string(responseBody))
}
return nil
}
// CheckResponseCode 检查API响应码
//
// 参数:
// - code: 响应码
// - message: 响应消息
//
// 返回: 错误信息
func CheckResponseCode(code int, message string) error {
if code != 0 {
return fmt.Errorf("API调用失败: %s", message)
}
return nil
}
// sortURLQueryParams 对URL查询参数按字典序ASCII码升序排序
//
// 参数:
// - urlPath: 包含查询参数的URL路径
//
// 返回: 排序后的URL路径
func sortURLQueryParams(urlPath string) string {
// 检查是否包含查询参数
if !strings.Contains(urlPath, "?") {
return urlPath
}
// 分离路径和查询参数
parts := strings.SplitN(urlPath, "?", 2)
if len(parts) != 2 {
return urlPath
}
basePath := parts[0]
queryString := parts[1]
// 解析查询参数
values, err := url.ParseQuery(queryString)
if err != nil {
// 如果解析失败,返回原始路径
return urlPath
}
// 获取所有参数键并排序
var keys []string
for key := range values {
keys = append(keys, key)
}
sort.Strings(keys)
// 重新构建查询字符串
var sortedPairs []string
for _, key := range keys {
for _, value := range values[key] {
sortedPairs = append(sortedPairs, key+"="+value)
}
}
// 组合排序后的查询参数
sortedQueryString := strings.Join(sortedPairs, "&")
// 返回完整的URL路径
if sortedQueryString != "" {
return basePath + "?" + sortedQueryString
}
return basePath
}

View File

@@ -0,0 +1,63 @@
package esign
import (
"fmt"
"net/url"
"strings"
)
// QueryOrgIdentityInfo 查询机构认证信息
// 根据orgId、orgName或orgIDCardNum查询机构实名认证信息
func (s *OrgAuthService) QueryOrgIdentityInfo(req *QueryOrgIdentityRequest) (*QueryOrgIdentityResponse, error) {
// 构建查询参数
params := url.Values{}
if req.OrgID != "" {
params.Add("orgId", req.OrgID)
} else if req.OrgName != "" {
params.Add("orgName", req.OrgName)
} else if req.OrgIDCardNum != "" {
params.Add("orgIDCardNum", req.OrgIDCardNum)
if req.OrgIDCardType != "" {
params.Add("orgIDCardType", string(req.OrgIDCardType))
}
} else {
return nil, fmt.Errorf("至少提供orgId, orgName或orgIDCardNum之一")
}
// 构建urlPath带query - 不使用URL编码保持原始参数值
urlPath := "/v3/organizations/identity-info"
if len(params) > 0 {
var queryParts []string
for key, values := range params {
for _, value := range values {
queryParts = append(queryParts, key+"="+value)
}
}
urlPath += "?" + strings.Join(queryParts, "&")
}
// 发送API请求
responseBody, err := s.httpClient.Request("GET", urlPath, nil)
if err != nil {
return nil, fmt.Errorf("查询机构认证信息失败: %v", err)
}
// 解析响应
var response QueryOrgIdentityResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return nil, err
}
if err := CheckResponseCode(int(response.Code), response.Message); err != nil {
return nil, err
}
fmt.Printf("查询机构认证信息成功!\n")
return &response, nil
}
// QueryOrgIdentityInfo 查询机构认证信息(客户端方法)
// 通过Client提供的便捷方法
func (c *Client) QueryOrgIdentityInfo(req *QueryOrgIdentityRequest) (*QueryOrgIdentityResponse, error) {
return c.orgAuth.QueryOrgIdentityInfo(req)
}

View File

@@ -0,0 +1,205 @@
package esign
import (
"fmt"
)
// OrgAuthService 机构认证服务
// 处理机构认证和授权相关操作
type OrgAuthService struct {
httpClient *HTTPClient
config *Config
}
// NewOrgAuthService 创建机构认证服务
func NewOrgAuthService(httpClient *HTTPClient, config *Config) *OrgAuthService {
return &OrgAuthService{
httpClient: httpClient,
config: config,
}
}
// UpdateConfig 更新配置
func (s *OrgAuthService) UpdateConfig(config *Config) {
s.config = config
}
// OrgAuthRequest 机构认证请求
type OrgAuthRequest struct {
OrgName string `json:"orgName"` // 机构名称
OrgIDCardNum string `json:"orgIdCardNum"` // 机构证件号
LegalRepName string `json:"legalRepName"` // 法定代表人姓名
LegalRepIDCardNum string `json:"legalRepIdCardNum"` // 法定代表人身份证号
TransactorName string `json:"transactorName"` // 经办人姓名
TransactorIDCardNum string `json:"transactorIdCardNum"` // 经办人身份证号
TransactorMobile string `json:"transactorMobile"` // 经办人手机号
}
// GetAuthURL 获取机构认证&授权页面链接
// 为机构用户获取认证和授权页面链接,用于机构身份认证
func (s *OrgAuthService) GetAuthURL(req *OrgAuthRequest) (string, string, string, error) {
// 构建请求数据
requestData := GetOrgAuthUrlRequest{
OrgAuthConfig: &OrgAuthConfig{
OrgName: req.OrgName,
OrgInfo: &OrgAuthInfo{
OrgIDCardNum: req.OrgIDCardNum,
OrgIDCardType: OrgCardTypeUSCC,
LegalRepName: req.LegalRepName,
LegalRepIDCardNum: req.LegalRepIDCardNum,
LegalRepIDCardType: IDCardTypeChina,
},
TransactorAuthPageConfig: &TransactorAuthPageConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
PsnDefaultAuthMode: AuthModeMobile3,
PsnEditableFields: []string{},
},
TransactorInfo: &TransactorAuthInfo{
PsnAccount: req.TransactorMobile,
PsnInfo: &PsnAuthInfo{
PsnName: req.TransactorName,
PsnIDCardNum: req.TransactorIDCardNum,
PsnIDCardType: IDCardTypeChina,
PsnMobile: req.TransactorMobile,
PsnIdentityVerify: true,
},
},
},
ClientType: ClientTypeAll,
}
// 序列化请求数据
jsonData, err := MarshalRequest(requestData)
if err != nil {
return "", "", "", err
}
fmt.Printf("获取机构认证&授权页面链接请求数据: %s\n", string(jsonData))
// 发送API请求
responseBody, err := s.httpClient.Request("POST", "/v3/org-auth-url", jsonData)
if err != nil {
return "", "", "", fmt.Errorf("获取机构认证&授权页面链接失败: %v", err)
}
// 解析响应
var response GetOrgAuthUrlResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return "", "", "", err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return "", "", "", err
}
fmt.Printf("机构认证&授权页面链接获取成功!\n")
fmt.Printf("认证流程ID: %s\n", response.Data.AuthFlowId)
fmt.Printf("完整链接: %s\n", response.Data.AuthUrl)
fmt.Printf("短链接: %s\n", response.Data.AuthShortUrl)
return response.Data.AuthFlowId, response.Data.AuthUrl, response.Data.AuthShortUrl, nil
}
// CreateAuthConfig 创建机构认证配置
// 构建机构认证所需的配置信息
func (s *OrgAuthService) CreateAuthConfig(req *OrgAuthRequest) *OrgAuthConfig {
return &OrgAuthConfig{
OrgName: req.OrgName,
OrgInfo: &OrgAuthInfo{
OrgIDCardNum: req.OrgIDCardNum,
OrgIDCardType: OrgCardTypeUSCC,
LegalRepName: req.LegalRepName,
LegalRepIDCardNum: req.LegalRepIDCardNum,
LegalRepIDCardType: IDCardTypeChina,
},
TransactorAuthPageConfig: &TransactorAuthPageConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
PsnDefaultAuthMode: AuthModeMobile3,
PsnEditableFields: []string{},
},
TransactorInfo: &TransactorAuthInfo{
PsnAccount: req.TransactorMobile,
PsnInfo: &PsnAuthInfo{
PsnName: req.TransactorName,
PsnIDCardNum: req.TransactorIDCardNum,
PsnIDCardType: IDCardTypeChina,
PsnMobile: req.TransactorMobile,
PsnIdentityVerify: true,
},
},
}
}
// ValidateAuthInfo 验证机构认证信息
// 检查机构认证信息的完整性和格式
func (s *OrgAuthService) ValidateAuthInfo(req *OrgAuthRequest) error {
if req.OrgName == "" {
return fmt.Errorf("机构名称不能为空")
}
if req.OrgIDCardNum == "" {
return fmt.Errorf("机构证件号不能为空")
}
if req.LegalRepName == "" {
return fmt.Errorf("法定代表人姓名不能为空")
}
if req.LegalRepIDCardNum == "" {
return fmt.Errorf("法定代表人身份证号不能为空")
}
if req.TransactorName == "" {
return fmt.Errorf("经办人姓名不能为空")
}
if req.TransactorIDCardNum == "" {
return fmt.Errorf("经办人身份证号不能为空")
}
if req.TransactorMobile == "" {
return fmt.Errorf("经办人手机号不能为空")
}
// 验证统一社会信用代码格式18位
if len(req.OrgIDCardNum) != 18 {
return fmt.Errorf("机构证件号统一社会信用代码必须是18位")
}
// 验证身份证号格式18位
if len(req.LegalRepIDCardNum) != 18 {
return fmt.Errorf("法定代表人身份证号必须是18位")
}
if len(req.TransactorIDCardNum) != 18 {
return fmt.Errorf("经办人身份证号必须是18位")
}
// 验证手机号格式11位
if len(req.TransactorMobile) != 11 {
return fmt.Errorf("经办人手机号必须是11位")
}
return nil
}
// QueryOrgIdentity 查询机构认证信息
// 查询机构的实名认证状态和信息
func (s *OrgAuthService) QueryOrgIdentity(req *QueryOrgIdentityRequest) (*QueryOrgIdentityResponse, error) {
// 序列化请求数据
jsonData, err := MarshalRequest(req)
if err != nil {
return nil, err
}
// 发送API请求
responseBody, err := s.httpClient.Request("POST", "/v3/organizations/identity", jsonData)
if err != nil {
return nil, fmt.Errorf("查询机构认证信息失败: %v", err)
}
// 解析响应
var response QueryOrgIdentityResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return nil, err
}
if err := CheckResponseCode(int(response.Code), response.Message); err != nil {
return nil, err
}
return &response, nil
}

View File

@@ -0,0 +1,215 @@
package esign
import (
"fmt"
)
// SignFlowService 签署流程服务
// 处理签署流程创建、链接获取等操作
type SignFlowService struct {
httpClient *HTTPClient
config *Config
}
// NewSignFlowService 创建签署流程服务
func NewSignFlowService(httpClient *HTTPClient, config *Config) *SignFlowService {
return &SignFlowService{
httpClient: httpClient,
config: config,
}
}
// UpdateConfig 更新配置
func (s *SignFlowService) UpdateConfig(config *Config) {
s.config = config
}
// Create 创建签署流程
// 创建包含多个签署人的签署流程,支持自动盖章和手动签署
func (s *SignFlowService) Create(req *CreateSignFlowRequest) (string, error) {
fmt.Println("开始创建签署流程...")
fmt.Println("(将创建包含甲方自动盖章和乙方手动签署的流程)")
// 构建甲方签署人信息(自动盖章)
partyASigner := s.buildPartyASigner(req.FileID)
// 构建乙方签署人信息(手动签署)
partyBSigner := s.buildPartyBSigner(req.FileID, req.SignerAccount, req.SignerName, req.TransactorPhone, req.TransactorName, req.TransactorIDCardNum)
signers := []SignerInfo{partyASigner, partyBSigner}
// 构建请求数据
requestData := CreateSignFlowByFileRequest{
Docs: []DocInfo{
{
FileId: req.FileID,
FileName: "天远数据API合作协议.pdf",
},
},
SignFlowConfig: s.buildSignFlowConfig(),
Signers: signers,
}
// 序列化请求数据
jsonData, err := MarshalRequest(requestData)
if err != nil {
return "", err
}
fmt.Printf("发起签署请求数据: %s\n", string(jsonData))
// 发送API请求
responseBody, err := s.httpClient.Request("POST", "/v3/sign-flow/create-by-file", jsonData)
if err != nil {
return "", fmt.Errorf("发起签署失败: %v", err)
}
// 解析响应
var response CreateSignFlowByFileResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return "", err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return "", err
}
fmt.Printf("签署流程创建成功流程ID: %s\n", response.Data.SignFlowId)
return response.Data.SignFlowId, nil
}
// GetSignURL 获取签署页面链接
// 为指定的签署人获取签署页面链接
func (s *SignFlowService) GetSignURL(signFlowID, psnAccount, orgName string) (string, string, error) {
fmt.Println("开始获取签署页面链接...")
// 构建请求数据
requestData := GetSignUrlRequest{
NeedLogin: false,
UrlType: UrlTypeSign,
Operator: &Operator{
PsnAccount: psnAccount,
},
Organization: &Organization{
OrgName: orgName,
},
ClientType: ClientTypeAll,
}
// 序列化请求数据
jsonData, err := MarshalRequest(requestData)
if err != nil {
return "", "", err
}
fmt.Printf("获取签署页面链接请求数据: %s\n", string(jsonData))
// 发送API请求
urlPath := fmt.Sprintf("/v3/sign-flow/%s/sign-url", signFlowID)
responseBody, err := s.httpClient.Request("POST", urlPath, jsonData)
if err != nil {
return "", "", fmt.Errorf("获取签署页面链接失败: %v", err)
}
// 解析响应
var response GetSignUrlResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return "", "", err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return "", "", err
}
fmt.Printf("签署页面链接获取成功!\n")
fmt.Printf("完整链接: %s\n", response.Data.Url)
fmt.Printf("短链接: %s\n", response.Data.ShortUrl)
return response.Data.Url, response.Data.ShortUrl, nil
}
// buildPartyASigner 构建甲方签署人信息(自动盖章)
func (s *SignFlowService) buildPartyASigner(fileID string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{SignOrder: 1},
SignerType: SignerTypeOrg,
SignFields: []SignField{
{
CustomBizNum: "甲方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: true,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "1",
PositionX: 200,
PositionY: 200,
},
},
},
},
}
}
// buildPartyBSigner 构建乙方签署人信息(手动签署)
func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{
SignOrder: 2,
},
AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
WillingnessAuthModes: []string{WillingnessAuthSMS},
},
SignerType: SignerTypeOrg,
OrgSignerInfo: &OrgSignerInfo{
OrgName: signerName,
OrgInfo: &OrgInfo{
LegalRepName: transactorName,
LegalRepIDCardNum: transactorIDCardNum,
LegalRepIDCardType: IDCardTypeChina,
OrgIDCardNum: signerAccount,
OrgIDCardType: OrgCardTypeUSCC,
},
TransactorInfo: &TransactorInfo{
PsnAccount: transactorPhone,
PsnInfo: &PsnInfo{
PsnName: transactorName,
PsnIDCardNum: transactorIDCardNum,
PsnIDCardType: IDCardTypeChina,
},
},
},
SignFields: []SignField{
{
CustomBizNum: "乙方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: false,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "1",
PositionX: 458,
PositionY: 200,
},
},
},
},
}
}
// buildSignFlowConfig 构建签署流程配置
func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig {
return SignFlowConfig{
SignFlowTitle: "天远数据API合作协议签署",
SignFlowExpireTime: calculateExpireTime(7), // 7天后过期
AutoFinish: true, // 所有签署方完成后自动完结
AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
WillingnessAuthModes: []string{WillingnessAuthSMS},
},
ContractConfig: &ContractConfig{
AllowToRescind: false,
},
}
}

View File

@@ -0,0 +1,167 @@
package esign
import (
"fmt"
"time"
)
// TemplateService 模板服务
// 处理模板填写和文件生成相关操作
type TemplateService struct {
httpClient *HTTPClient
config *Config
}
// NewTemplateService 创建模板服务
func NewTemplateService(httpClient *HTTPClient, config *Config) *TemplateService {
return &TemplateService{
httpClient: httpClient,
config: config,
}
}
// UpdateConfig 更新配置
func (s *TemplateService) UpdateConfig(config *Config) {
s.config = config
}
// Fill 填写模板生成文件
// 根据模板ID和填写内容生成包含填写内容的文档
//
// 参数说明:
// - components: 需要填写的组件列表,包含字段键名和值
//
// 返回: 生成的文件ID和错误信息
func (s *TemplateService) Fill(components []Component) (*FillTemplate, error) {
fmt.Println("开始填写模板生成文件...")
// 生成带时间戳的文件名
fileName := generateFileName("天远数据API合作协议", "pdf")
// 构建请求数据
requestData := FillTemplateRequest{
DocTemplateID: s.config.TemplateID,
FileName: fileName,
Components: components,
}
// 序列化请求数据
jsonData, err := MarshalRequest(requestData)
if err != nil {
return nil, err
}
// 发送API请求
responseBody, err := s.httpClient.Request("POST", "/v3/files/create-by-doc-template", jsonData)
if err != nil {
return nil, fmt.Errorf("填写模板失败: %v", err)
}
// 解析响应
var response FillTemplateResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return nil, err
}
// 检查响应状态
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return nil, err
}
fmt.Printf("模板填写成功文件ID: %s\n", response.Data.FileID)
return &FillTemplate{
FileID: response.Data.FileID,
FileDownloadUrl: response.Data.FileDownloadUrl,
FileName: fileName,
TemplateID: s.config.TemplateID,
FillTime: time.Now(),
}, nil
}
// FillWithDefaults 使用默认数据填写模板
// 使用预设的默认数据填写模板,适用于测试或标准流程
//
// 参数说明:
// - partyA: 甲方企业名称
// - legalRepA: 甲方法人姓名
// - partyB: 乙方企业名称
// - legalRepB: 乙方法人姓名
//
// 返回: 生成的文件ID和错误信息
func (s *TemplateService) FillWithDefaults(partyA, legalRepA, partyB, legalRepB string) (*FillTemplate, error) {
// 构建默认填写组件
components := []Component{
{
ComponentKey: "JFQY",
ComponentValue: partyA,
},
{
ComponentKey: "JFFR",
ComponentValue: legalRepA,
},
{
ComponentKey: "YFQY",
ComponentValue: partyB,
},
{
ComponentKey: "YFFR",
ComponentValue: legalRepB,
},
{
ComponentKey: "QDRQ",
ComponentValue: formatDateForTemplate(),
},
}
return s.Fill(components)
}
// FillWithCustomData 使用自定义数据填写模板
// 允许传入自定义的组件数据来填写模板
//
// 参数说明:
// - customComponents: 自定义组件数据
//
// 返回: 生成的文件ID和错误信息
func (s *TemplateService) FillWithCustomData(customComponents map[string]string) (*FillTemplate, error) {
var components []Component
// 将map转换为Component切片
for key, value := range customComponents {
components = append(components, Component{
ComponentKey: key,
ComponentValue: value,
})
}
return s.Fill(components)
}
// CreateDefaultComponents 创建默认模板数据
// 返回用于测试的默认模板填写数据
//
// 返回: 默认组件数据
func CreateDefaultComponents() []Component {
return []Component{
{
ComponentKey: "JFQY",
ComponentValue: "海南省学宇思网络科技有限公司",
},
{
ComponentKey: "JFFR",
ComponentValue: "刘福思",
},
{
ComponentKey: "YFQY",
ComponentValue: "测试企业",
},
{
ComponentKey: "YFFR",
ComponentValue: "测试法人",
},
{
ComponentKey: "QDRQ",
ComponentValue: time.Now().Format("2006年01月02日"),
},
}
}

View File

@@ -0,0 +1,571 @@
package esign
import "time"
// ==================== 模板填写相关结构体 ====================
// FillTemplateRequest 模板填写请求结构体
// 用于根据模板ID生成包含填写内容的文档
type FillTemplateRequest struct {
DocTemplateID string `json:"docTemplateId"` // 文档模板ID
FileName string `json:"fileName"` // 生成的文件名
Components []Component `json:"components"` // 填写组件列表
}
// Component 控件结构体
// 定义模板中需要填写的字段信息
type Component struct {
ComponentID string `json:"componentId,omitempty"` // 控件ID可选
ComponentKey string `json:"componentKey,omitempty"` // 控件键名(可选)
ComponentValue string `json:"componentValue"` // 控件值
}
// FillTemplateResponse 模板填写响应结构体
type FillTemplateResponse struct {
Code int `json:"code"` // 响应码
Message string `json:"message"` // 响应消息
Data struct {
FileID string `json:"fileId"` // 生成的文件ID
FileDownloadUrl string `json:"fileDownloadUrl"` // 文件下载URL
} `json:"data"`
}
type FillTemplate struct {
FileID string `json:"fileId"` // 生成的文件ID
FileDownloadUrl string `json:"fileDownloadUrl"` // 文件下载URL
FileName string `json:"fileName"` // 文件名
TemplateID string `json:"templateId"` // 模板ID
FillTime time.Time `json:"fillTime"` // 填写时间
}
// ==================== 签署流程相关结构体 ====================
// CreateSignFlowByFileRequest 发起签署请求结构体
// 用于创建基于文件的签署流程
type CreateSignFlowByFileRequest struct {
Docs []DocInfo `json:"docs"` // 文档信息列表
SignFlowConfig SignFlowConfig `json:"signFlowConfig"` // 签署流程配置
Signers []SignerInfo `json:"signers"` // 签署人列表
}
// CreateSignFlowByFileResponse 发起签署响应结构体
type CreateSignFlowByFileResponse struct {
Code int `json:"code"` // 响应码
Message string `json:"message"` // 响应消息
Data struct {
SignFlowId string `json:"signFlowId"` // 签署流程ID
} `json:"data"`
}
// DocInfo 文档信息
type DocInfo struct {
FileId string `json:"fileId"` // 文件ID
FileName string `json:"fileName"` // 文件名
}
// SignFlowConfig 签署流程配置
type SignFlowConfig struct {
SignFlowTitle string `json:"signFlowTitle"` // 签署流程标题
SignFlowExpireTime int64 `json:"signFlowExpireTime,omitempty"` // 签署流程过期时间
AutoFinish bool `json:"autoFinish"` // 是否自动完结
NotifyUrl string `json:"notifyUrl,omitempty"` // 回调通知URL
RedirectConfig *RedirectConfig `json:"redirectConfig,omitempty"` // 重定向配置
AuthConfig *AuthConfig `json:"authConfig,omitempty"` // 认证配置
ContractConfig *ContractConfig `json:"contractConfig,omitempty"` // 合同配置
}
// RedirectConfig 重定向配置
type RedirectConfig struct {
RedirectUrl string `json:"redirectUrl"` // 重定向URL
}
// AuthConfig 认证配置
type AuthConfig struct {
PsnAvailableAuthModes []string `json:"psnAvailableAuthModes"` // 个人可用认证模式
OrgAvailableAuthModes []string `json:"orgAvailableAuthModes"` // 机构可用认证模式
WillingnessAuthModes []string `json:"willingnessAuthModes"` // 意愿认证模式
AudioVideoTemplateId string `json:"audioVideoTemplateId"` // 音视频模板ID
}
// ContractConfig 合同配置
type ContractConfig struct {
AllowToRescind bool `json:"allowToRescind"` // 是否允许撤销
}
// ==================== 签署人相关结构体 ====================
// SignerInfo 签署人信息结构体
type SignerInfo struct {
SignConfig *SignConfig `json:"signConfig"` // 签署配置
AuthConfig *AuthConfig `json:"authConfig"` // 认证配置
NoticeConfig *NoticeConfig `json:"noticeConfig"` // 通知配置
SignerType int `json:"signerType"` // 签署人类型0-个人1-机构
PsnSignerInfo *PsnSignerInfo `json:"psnSignerInfo,omitempty"` // 个人签署人信息
OrgSignerInfo *OrgSignerInfo `json:"orgSignerInfo,omitempty"` // 机构签署人信息
SignFields []SignField `json:"signFields"` // 签署区列表
}
// SignConfig 签署配置
type SignConfig struct {
SignOrder int `json:"signOrder"` // 签署顺序
}
// NoticeConfig 通知配置
type NoticeConfig struct {
NoticeTypes string `json:"noticeTypes"` // 通知类型1-短信2-邮件3-短信+邮件
}
// PsnSignerInfo 个人签署人信息
type PsnSignerInfo struct {
PsnAccount string `json:"psnAccount"` // 个人账号
PsnInfo *PsnInfo `json:"psnInfo"` // 个人信息
}
// PsnInfo 个人基本信息
type PsnInfo struct {
PsnName string `json:"psnName"` // 个人姓名
PsnIDCardNum string `json:"psnIDCardNum,omitempty"` // 身份证号
PsnIDCardType string `json:"psnIDCardType,omitempty"` // 证件类型
BankCardNum string `json:"bankCardNum,omitempty"` // 银行卡号
}
// OrgSignerInfo 机构签署人信息
type OrgSignerInfo struct {
OrgName string `json:"orgName"` // 机构名称
OrgInfo *OrgInfo `json:"orgInfo"` // 机构信息
TransactorInfo *TransactorInfo `json:"transactorInfo"` // 经办人信息
}
// OrgInfo 机构信息
type OrgInfo struct {
LegalRepName string `json:"legalRepName"` // 法定代表人姓名
LegalRepIDCardNum string `json:"legalRepIDCardNum"` // 法定代表人身份证号
LegalRepIDCardType string `json:"legalRepIDCardType"` // 法定代表人证件类型
OrgIDCardNum string `json:"orgIDCardNum"` // 机构证件号
OrgIDCardType string `json:"orgIDCardType"` // 机构证件类型
}
// TransactorInfo 经办人信息
type TransactorInfo struct {
PsnAccount string `json:"psnAccount"` // 经办人账号
PsnInfo *PsnInfo `json:"psnInfo"` // 经办人信息
}
// ==================== 签署区相关结构体 ====================
// SignField 签署区信息
type SignField struct {
CustomBizNum string `json:"customBizNum"` // 自定义业务号
FileId string `json:"fileId"` // 文件ID
NormalSignFieldConfig *NormalSignFieldConfig `json:"normalSignFieldConfig"` // 普通签署区配置
}
// NormalSignFieldConfig 普通签署区配置
type NormalSignFieldConfig struct {
AutoSign bool `json:"autoSign,omitempty"` // 是否自动签署
SignFieldStyle int `json:"signFieldStyle"` // 签署区样式1-普通签章2-骑缝签章
SignFieldPosition *SignFieldPosition `json:"signFieldPosition"` // 签署区位置
}
// SignFieldPosition 签署区位置
type SignFieldPosition struct {
PositionPage string `json:"positionPage"` // 页码
PositionX float64 `json:"positionX"` // X坐标
PositionY float64 `json:"positionY"` // Y坐标
}
// ==================== 签署页面链接相关结构体 ====================
// GetSignUrlRequest 获取签署页面链接请求结构体
type GetSignUrlRequest struct {
NeedLogin bool `json:"needLogin,omitempty"` // 是否需要登录
UrlType int `json:"urlType,omitempty"` // URL类型
Operator *Operator `json:"operator"` // 操作人信息
Organization *Organization `json:"organization,omitempty"` // 机构信息
RedirectConfig *RedirectConfig `json:"redirectConfig,omitempty"` // 重定向配置
ClientType string `json:"clientType,omitempty"` // 客户端类型
AppScheme string `json:"appScheme,omitempty"` // 应用协议
}
// Operator 操作人信息
type Operator struct {
PsnAccount string `json:"psnAccount,omitempty"` // 个人账号
PsnId string `json:"psnId,omitempty"` // 个人ID
}
// Organization 机构信息
type Organization struct {
OrgId string `json:"orgId,omitempty"` // 机构ID
OrgName string `json:"orgName,omitempty"` // 机构名称
}
// GetSignUrlResponse 获取签署页面链接响应结构体
type GetSignUrlResponse struct {
Code int `json:"code"` // 响应码
Message string `json:"message"` // 响应消息
Data struct {
ShortUrl string `json:"shortUrl"` // 短链接
Url string `json:"url"` // 完整链接
} `json:"data"`
}
// ==================== 文件下载相关结构体 ====================
// DownloadSignedFileResponse 下载已签署文件响应结构体
type DownloadSignedFileResponse struct {
Code int `json:"code"` // 响应码
Message string `json:"message"` // 响应消息
Data struct {
Files []SignedFileInfo `json:"files"` // 已签署文件列表
Attachments []SignedFileInfo `json:"attachments"` // 附属材料列表
CertificateDownloadUrl string `json:"certificateDownloadUrl"` // 证书下载链接
} `json:"data"`
}
// SignedFileInfo 已签署文件信息
type SignedFileInfo struct {
FileId string `json:"fileId"` // 文件ID
FileName string `json:"fileName"` // 文件名
DownloadUrl string `json:"downloadUrl"` // 下载链接
}
// ==================== 流程查询相关结构体 ====================
// QuerySignFlowDetailResponse 查询签署流程详情响应结构体
type QuerySignFlowDetailResponse struct {
Code int `json:"code"` // 响应码
Message string `json:"message"` // 响应消息
Data struct {
SignFlowStatus int32 `json:"signFlowStatus"` // 签署流程状态
SignFlowDescription string `json:"signFlowDescription"` // 签署流程描述
RescissionStatus int32 `json:"rescissionStatus"` // 撤销状态
RescissionSignFlowIds []string `json:"rescissionSignFlowIds"` // 撤销的签署流程ID列表
RevokeReason string `json:"revokeReason"` // 撤销原因
SignFlowCreateTime int64 `json:"signFlowCreateTime"` // 签署流程创建时间
SignFlowStartTime int64 `json:"signFlowStartTime"` // 签署流程开始时间
SignFlowFinishTime int64 `json:"signFlowFinishTime"` // 签署流程完成时间
SignFlowInitiator *SignFlowInitiator `json:"signFlowInitiator"` // 签署流程发起方
SignFlowConfig *SignFlowConfigDetail `json:"signFlowConfig"` // 签署流程配置详情
Docs []DocDetail `json:"docs"` // 文档详情列表
Attachments []AttachmentDetail `json:"attachments"` // 附属材料详情列表
Signers []SignerDetail `json:"signers"` // 签署人详情列表
Copiers []CopierDetail `json:"copiers"` // 抄送方详情列表
} `json:"data"`
}
// SignFlowInitiator 签署流程发起方
type SignFlowInitiator struct {
PsnInitiator *PsnInitiator `json:"psnInitiator"` // 个人发起方
OrgInitiator *OrgInitiator `json:"orgInitiator"` // 机构发起方
}
// PsnInitiator 个人发起方
type PsnInitiator struct {
PsnId string `json:"psnId"` // 个人ID
PsnName string `json:"psnName"` // 个人姓名
}
// OrgInitiator 机构发起方
type OrgInitiator struct {
OrgId string `json:"orgId"` // 机构ID
OrgName string `json:"orgName"` // 机构名称
Transactor *Transactor `json:"transactor"` // 经办人
}
// Transactor 经办人
type Transactor struct {
PsnId string `json:"psnId"` // 个人ID
PsnName string `json:"psnName"` // 个人姓名
}
// SignFlowConfigDetail 签署流程配置详情
type SignFlowConfigDetail struct {
SignFlowTitle string `json:"signFlowTitle"` // 签署流程标题
ContractGroupIds []string `json:"contractGroupIds"` // 合同组ID列表
AutoFinish bool `json:"autoFinish"` // 是否自动完结
SignFlowExpireTime int64 `json:"signFlowExpireTime"` // 签署流程过期时间
NotifyUrl string `json:"notifyUrl"` // 回调通知URL
ChargeConfig *ChargeConfig `json:"chargeConfig"` // 计费配置
NoticeConfig *NoticeConfig `json:"noticeConfig"` // 通知配置
SignConfig *SignConfigDetail `json:"signConfig"` // 签署配置详情
AuthConfig *AuthConfig `json:"authConfig"` // 认证配置
}
// ChargeConfig 计费配置
type ChargeConfig struct {
ChargeMode int `json:"chargeMode"` // 计费模式
OrderType string `json:"orderType"` // 订单类型
BarrierCode string `json:"barrierCode"` // 障碍码
}
// SignConfigDetail 签署配置详情
type SignConfigDetail struct {
AvailableSignClientTypes string `json:"availableSignClientTypes"` // 可用签署客户端类型
ShowBatchDropSealButton bool `json:"showBatchDropSealButton"` // 是否显示批量盖章按钮
SignTipsTitle string `json:"signTipsTitle"` // 签署提示标题
SignTipsContent string `json:"signTipsContent"` // 签署提示内容
SignMode string `json:"signMode"` // 签署模式
DedicatedCloudId string `json:"dedicatedCloudId"` // 专属云ID
}
// DocDetail 文档详情
type DocDetail struct {
FileId string `json:"fileId"` // 文件ID
FileName string `json:"fileName"` // 文件名
FileEditPwd string `json:"fileEditPwd"` // 文件编辑密码
ContractNum string `json:"contractNum"` // 合同编号
ContractBizTypeId string `json:"contractBizTypeId"` // 合同业务类型ID
}
// AttachmentDetail 附属材料详情
type AttachmentDetail struct {
FileId string `json:"fileId"` // 文件ID
FileName string `json:"fileName"` // 文件名
SignerUpload bool `json:"signerUpload"` // 是否签署人上传
}
// CopierDetail 抄送方详情
type CopierDetail struct {
CopierPsnInfo *CopierPsnInfo `json:"copierPsnInfo"` // 个人抄送方
CopierOrgInfo *CopierOrgInfo `json:"copierOrgInfo"` // 机构抄送方
}
// CopierPsnInfo 个人抄送方
type CopierPsnInfo struct {
PsnId string `json:"psnId"` // 个人ID
PsnAccount string `json:"psnAccount"` // 个人账号
}
// CopierOrgInfo 机构抄送方
type CopierOrgInfo struct {
OrgId string `json:"orgId"` // 机构ID
OrgName string `json:"orgName"` // 机构名称
}
// SignerDetail 签署人详情
type SignerDetail struct {
PsnSigner *PsnSignerDetail `json:"psnSigner,omitempty"` // 个人签署人详情
OrgSigner *OrgSignerDetail `json:"orgSigner,omitempty"` // 机构签署人详情
SignerType int `json:"signerType"` // 签署人类型
SignOrder int `json:"signOrder"` // 签署顺序
SignStatus int `json:"signStatus"` // 签署状态
SignFields []SignFieldDetail `json:"signFields"` // 签署区详情列表
}
// PsnSignerDetail 个人签署人详情
type PsnSignerDetail struct {
PsnId string `json:"psnId"` // 个人ID
PsnName string `json:"psnName"` // 个人姓名
PsnAccount *PsnAccount `json:"psnAccount"` // 个人账号信息
}
// PsnAccount 个人账号信息
type PsnAccount struct {
AccountMobile string `json:"accountMobile"` // 账号手机号
AccountEmail string `json:"accountEmail"` // 账号邮箱
}
// OrgSignerDetail 机构签署人详情
type OrgSignerDetail struct {
OrgId string `json:"orgId"` // 机构ID
OrgName string `json:"orgName"` // 机构名称
OrgAccount string `json:"orgAccount"` // 机构账号
}
// SignFieldDetail 签署区详情
type SignFieldDetail struct {
SignFieldId string `json:"signFieldId"` // 签署区ID
SignFieldStatus string `json:"signFieldStatus"` // 签署区状态
SealApprovalFlowId string `json:"sealApprovalFlowId"` // 印章审批流程ID
StatusUpdateTime int64 `json:"statusUpdateTime"` // 状态更新时间
FailReason string `json:"failReason"` // 失败原因
CustomBizNum string `json:"customBizNum"` // 自定义业务号
FileId string `json:"fileId"` // 文件ID
SignFieldType int `json:"signFieldType"` // 签署区类型
MustSign bool `json:"mustSign"` // 是否必须签署
SignFieldSealType int `json:"signFieldSealType"` // 签署区印章类型
NormalSignFieldConfig *NormalSignFieldDetail `json:"normalSignFieldConfig"` // 普通签署区配置详情
}
// NormalSignFieldDetail 普通签署区配置详情
type NormalSignFieldDetail struct {
FreeMode bool `json:"freeMode"` // 是否自由模式
SignFieldStyle int `json:"signFieldStyle"` // 签署区样式
SignFieldPosition *SignFieldPosition `json:"signFieldPosition"` // 签署区位置
MovableSignField bool `json:"movableSignField"` // 是否可移动签署区
AutoSign bool `json:"autoSign"` // 是否自动签署
SealStyle string `json:"sealStyle"` // 印章样式
SealId string `json:"sealId"` // 印章ID
}
// ==================== 机构认证相关结构体 ====================
// GetOrgAuthUrlRequest 获取机构认证&授权页面链接请求结构体
type GetOrgAuthUrlRequest struct {
OrgAuthConfig *OrgAuthConfig `json:"orgAuthConfig"` // 机构认证配置
AuthorizeConfig *AuthorizeConfig `json:"authorizeConfig,omitempty"` // 授权配置
RedirectConfig *RedirectConfig `json:"redirectConfig,omitempty"` // 重定向配置
ClientType string `json:"clientType,omitempty"` // 客户端类型
NotifyUrl string `json:"notifyUrl,omitempty"` // 回调通知URL
AppScheme string `json:"appScheme,omitempty"` // 应用协议
}
// OrgAuthConfig 机构认证授权相关结构体
type OrgAuthConfig struct {
OrgName string `json:"orgName,omitempty"` // 机构名称
OrgId string `json:"orgId,omitempty"` // 机构ID
OrgInfo *OrgAuthInfo `json:"orgInfo,omitempty"` // 机构信息
TransactorAuthPageConfig *TransactorAuthPageConfig `json:"transactorAuthPageConfig,omitempty"` // 经办人认证页面配置
TransactorInfo *TransactorAuthInfo `json:"transactorInfo,omitempty"` // 经办人信息
}
// OrgAuthInfo 机构认证信息
type OrgAuthInfo struct {
OrgIDCardNum string `json:"orgIDCardNum,omitempty"` // 机构证件号
OrgIDCardType string `json:"orgIDCardType,omitempty"` // 机构证件类型
LegalRepName string `json:"legalRepName,omitempty"` // 法定代表人姓名
LegalRepIDCardNum string `json:"legalRepIDCardNum,omitempty"` // 法定代表人身份证号
LegalRepIDCardType string `json:"legalRepIDCardType,omitempty"` // 法定代表人证件类型
OrgBankAccountNum string `json:"orgBankAccountNum,omitempty"` // 机构银行账号
}
// TransactorAuthPageConfig 经办人认证页面配置
type TransactorAuthPageConfig struct {
PsnAvailableAuthModes []string `json:"psnAvailableAuthModes,omitempty"` // 个人可用认证模式
PsnDefaultAuthMode string `json:"psnDefaultAuthMode,omitempty"` // 个人默认认证模式
PsnEditableFields []string `json:"psnEditableFields,omitempty"` // 个人可编辑字段
}
// TransactorAuthInfo 经办人认证信息
type TransactorAuthInfo struct {
PsnAccount string `json:"psnAccount,omitempty"` // 经办人账号
PsnInfo *PsnAuthInfo `json:"psnInfo,omitempty"` // 经办人信息
}
// PsnAuthInfo 个人认证信息
type PsnAuthInfo struct {
PsnName string `json:"psnName,omitempty"` // 个人姓名
PsnIDCardNum string `json:"psnIDCardNum,omitempty"` // 身份证号
PsnIDCardType string `json:"psnIDCardType,omitempty"` // 证件类型
PsnMobile string `json:"psnMobile,omitempty"` // 手机号
PsnIdentityVerify bool `json:"psnIdentityVerify,omitempty"` // 是否身份验证
}
// AuthorizeConfig 授权配置
type AuthorizeConfig struct {
AuthorizedScopes []string `json:"authorizedScopes,omitempty"` // 授权范围
}
// GetOrgAuthUrlResponse 获取机构认证&授权页面链接响应结构体
type GetOrgAuthUrlResponse struct {
Code int `json:"code"` // 响应码
Message string `json:"message"` // 响应消息
Data struct {
AuthFlowId string `json:"authFlowId"` // 认证流程ID
AuthUrl string `json:"authUrl"` // 认证链接
AuthShortUrl string `json:"authShortUrl"` // 认证短链接
} `json:"data"`
}
// ==================== 机构认证查询相关结构体 ====================
type OrgIDCardType string
const (
OrgIDCardTypeUSCC OrgIDCardType = "CRED_ORG_USCC" // 统一社会信用代码
OrgIDCardTypeREGCODE OrgIDCardType = "CRED_ORG_REGCODE" // 工商注册号
)
// QueryOrgIdentityRequest 查询机构认证信息请求
type QueryOrgIdentityRequest struct {
OrgID string `json:"orgId,omitempty"` // 机构账号ID
OrgName string `json:"orgName,omitempty"` // 组织机构名称
OrgIDCardNum string `json:"orgIDCardNum,omitempty"` // 组织机构证件号
OrgIDCardType OrgIDCardType `json:"orgIDCardType,omitempty"` // 组织机构证件类型只能为OrgIDCardTypeUSCC或OrgIDCardTypeREGCODE
}
// QueryOrgIdentityResponse 查询机构认证信息响应
type QueryOrgIdentityResponse struct {
Code int32 `json:"code"` // 业务码0表示成功
Message string `json:"message"` // 业务信息
Data struct {
RealnameStatus int32 `json:"realnameStatus"` // 实名认证状态 (0-未实名, 1-已实名)
AuthorizeUserInfo bool `json:"authorizeUserInfo"` // 是否授权身份信息给当前应用
OrgID string `json:"orgId"` // 机构账号ID
OrgName string `json:"orgName"` // 机构名称
OrgAuthMode string `json:"orgAuthMode"` // 机构实名认证方式
OrgInfo struct {
OrgIDCardNum string `json:"orgIDCardNum"` // 组织机构证件号
OrgIDCardType string `json:"orgIDCardType"` // 组织机构证件号类型
LegalRepName string `json:"legalRepName"` // 法定代表人姓名
LegalRepIDCardNum string `json:"legalRepIDCardNum"` // 法定代表人证件号
LegalRepIDCardType string `json:"legalRepIDCardType"` // 法定代表人证件类型
CorporateAccount string `json:"corporateAccount"` // 机构对公账户名称
OrgBankAccountNum string `json:"orgBankAccountNum"` // 机构对公打款银行卡号
CnapsCode string `json:"cnapsCode"` // 机构对公打款银行联行号
AuthorizationDownloadUrl string `json:"authorizationDownloadUrl"` // 授权委托书下载地址
LicenseDownloadUrl string `json:"licenseDownloadUrl"` // 营业执照照片下载地址
AdminName string `json:"adminName"` // 机构管理员姓名(脱敏)
AdminAccount string `json:"adminAccount"` // 机构管理员联系方式(脱敏)
} `json:"orgInfo"`
} `json:"data"`
}
// ==================== 结果结构体 ====================
// SignResult 签署结果结构体
// 包含签署流程的完整结果信息
type SignResult struct {
FileID string `json:"fileId"` // 文件ID
SignFlowID string `json:"signFlowId"` // 签署流程ID
SignUrl string `json:"signUrl"` // 签署链接
ShortUrl string `json:"shortUrl"` // 短链接
DownloadSignedFileResult *DownloadSignedFileResponse `json:"downloadSignedFileResult,omitempty"` // 下载已签署文件结果
QuerySignFlowDetailResult *QuerySignFlowDetailResponse `json:"querySignFlowDetailResult,omitempty"` // 查询签署流程详情结果
}
// ==================== 请求结构体优化 ====================
// SignProcessRequest 签署流程请求结构体
type SignProcessRequest struct {
SignerAccount string `json:"signerAccount"` // 签署人账号(统一社会信用代码)
SignerName string `json:"signerName"` // 签署人名称
TransactorPhone string `json:"transactorPhone"` // 经办人手机号
TransactorName string `json:"transactorName"` // 经办人姓名
TransactorIDCardNum string `json:"transactorIdCardNum"` // 经办人身份证号
TransactorMobile string `json:"transactorMobile"` // 经办人手机号
IncludeDownloadAndQuery bool `json:"includeDownloadAndQuery"` // 是否包含下载和查询步骤
CustomComponents map[string]string `json:"customComponents,omitempty"` // 自定义模板组件数据
}
// OrgAuthUrlRequest 机构认证链接请求结构体
type OrgAuthUrlRequest struct {
OrgName string `json:"orgName"` // 机构名称
OrgIDCardNum string `json:"orgIdCardNum"` // 机构证件号
LegalRepName string `json:"legalRepName"` // 法定代表人姓名
LegalRepIDCardNum string `json:"legalRepIdCardNum"` // 法定代表人身份证号
TransactorPhone string `json:"transactorPhone"` // 经办人手机号
TransactorName string `json:"transactorName"` // 经办人姓名
TransactorIDCardNum string `json:"transactorIdCardNum"` // 经办人身份证号
TransactorMobile string `json:"transactorMobile"` // 经办人手机号
}
// CreateSignFlowRequest 创建签署流程请求结构体
type CreateSignFlowRequest struct {
FileID string `json:"fileId"` // 文件ID
SignerAccount string `json:"signerAccount"` // 签署人账号
SignerName string `json:"signerName"` // 签署人名称
TransactorPhone string `json:"transactorPhone"` // 经办人手机号
TransactorName string `json:"transactorName"` // 经办人姓名
TransactorIDCardNum string `json:"transactorIdCardNum"` // 经办人身份证号
}
// SimplifiedGetSignUrlRequest 简化获取签署链接请求结构体 (避免与现有冲突)
type SimplifiedGetSignUrlRequest struct {
SignFlowID string `json:"signFlowId"` // 签署流程ID
PsnAccount string `json:"psnAccount"` // 个人账号(手机号)
OrgName string `json:"orgName"` // 机构名称
}
// SimplifiedFillTemplateRequest 简化填写模板请求结构体
type SimplifiedFillTemplateRequest struct {
Components []Component `json:"components"` // 填写组件列表
}

View File

@@ -0,0 +1,104 @@
package esign
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/base64"
"strconv"
"time"
)
// generateSignature 生成e签宝API请求签名
// 使用HMAC-SHA256算法对请求参数进行签名
//
// 参数说明:
// - appSecret: 应用密钥
// - httpMethod: HTTP方法GET、POST等
// - accept: Accept头值
// - contentMD5: 请求体MD5值
// - contentType: Content-Type头值
// - date: Date头值
// - headers: 自定义头部信息
// - pathAndParameters: 请求路径和参数
//
// 返回: Base64编码的签名字符串
func generateSignature(appSecret, httpMethod, accept, contentMD5, contentType, date, headers, pathAndParameters string) string {
// 构建待签名字符串按照e签宝API规范拼接
signStr := httpMethod + "\n" + accept + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n" + headers + pathAndParameters
// 使用HMAC-SHA256计算签名
h := hmac.New(sha256.New, []byte(appSecret))
h.Write([]byte(signStr))
digestBytes := h.Sum(nil)
// 对摘要结果进行Base64编码
signature := base64.StdEncoding.EncodeToString(digestBytes)
return signature
}
// generateNonce 生成随机字符串
// 使用当前时间的纳秒数作为随机字符串
//
// 返回: 纳秒时间戳字符串
func generateNonce() string {
return strconv.FormatInt(time.Now().UnixNano(), 10)
}
// getContentMD5 计算请求体的MD5值
// 对请求体进行MD5哈希计算然后进行Base64编码
//
// 参数:
// - body: 请求体字节数组
//
// 返回: Base64编码的MD5值
func getContentMD5(body []byte) string {
md5Sum := md5.Sum(body)
return base64.StdEncoding.EncodeToString(md5Sum[:])
}
// getCurrentTimestamp 获取当前时间戳(毫秒)
//
// 返回: 毫秒级时间戳字符串
func getCurrentTimestamp() string {
return strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
}
// getCurrentDate 获取当前UTC时间字符串
// 格式: "Mon, 02 Jan 2006 15:04:05 GMT"
//
// 返回: RFC1123格式的UTC时间字符串
func getCurrentDate() string {
return time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT")
}
// formatDateForTemplate 格式化日期用于模板填写
// 格式: "2006年01月02日"
//
// 返回: 中文格式的日期字符串
func formatDateForTemplate() string {
return time.Now().Format("2006年01月02日")
}
// generateFileName 生成带时间戳的文件名
//
// 参数:
// - baseName: 基础文件名
// - extension: 文件扩展名
//
// 返回: 带时间戳的文件名
func generateFileName(baseName, extension string) string {
timestamp := time.Now().Format("20060102_150405")
return baseName + "_" + timestamp + "." + extension
}
// calculateExpireTime 计算过期时间戳
//
// 参数:
// - days: 过期天数
//
// 返回: 毫秒级时间戳
func calculateExpireTime(days int) int64 {
return time.Now().AddDate(0, 0, days).UnixMilli()
}