Quellcode durchsuchen

feat: 支持下载机构电子公章图片

新增 DeriveCompanySealName、CompanySealImage 及 Base64 封装,供 ngtm 查看印章接口使用。

Co-authored-by: Cursor <cursoragent@cursor.com>
郭铭泽 vor 5 Tagen
Ursprung
Commit
d135811b7b
3 geänderte Dateien mit 117 neuen und 0 gelöschten Zeilen
  1. 61 0
      client.go
  2. 2 0
      errors.go
  3. 54 0
      seal.go

+ 61 - 0
client.go

@@ -3,6 +3,7 @@ package qiyuesuosdk
 import (
 	"bytes"
 	"crypto/md5"
+	"encoding/base64"
 	"encoding/hex"
 	"encoding/json"
 	"fmt"
@@ -137,6 +138,66 @@ func (c *Client) postMultipart(path string, fields map[string]string, fileField
 	return c.doJSON(req, out)
 }
 
+func (c *Client) postForImageBytes(path string, body any) ([]byte, string, error) {
+	payload, err := json.Marshal(body)
+	if err != nil {
+		return nil, "", err
+	}
+	req, err := http.NewRequest(http.MethodPost, c.baseURL()+path, bytes.NewReader(payload))
+	if err != nil {
+		return nil, "", err
+	}
+	req.Header.Set("Content-Type", "application/json;charset=UTF-8")
+	req.Header.Set("Accept", "application/json,image/*,*/*")
+	for k, v := range c.authHeaders() {
+		req.Header.Set(k, v)
+	}
+	resp, err := c.http.Do(req)
+	if err != nil {
+		return nil, "", err
+	}
+	defer resp.Body.Close()
+	data, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return nil, "", err
+	}
+	contentType := strings.TrimSpace(strings.Split(resp.Header.Get("Content-Type"), ";")[0])
+	if len(data) > 0 && data[0] == '{' {
+		var wrapper struct {
+			apiResponse
+			Result json.RawMessage `json:"result"`
+		}
+		if err = json.Unmarshal(data, &wrapper); err != nil {
+			return nil, "", err
+		}
+		if err = wrapper.err(); err != nil {
+			return nil, "", err
+		}
+		if len(wrapper.Result) == 0 || string(wrapper.Result) == "null" {
+			return nil, "", ErrSealImageUnavailable
+		}
+		var resultStr string
+		if err = json.Unmarshal(wrapper.Result, &resultStr); err == nil && resultStr != "" {
+			img, decErr := base64.StdEncoding.DecodeString(resultStr)
+			if decErr != nil {
+				return nil, "", decErr
+			}
+			if contentType == "" {
+				contentType = "image/png"
+			}
+			return img, contentType, nil
+		}
+		return nil, "", ErrSealImageUnavailable
+	}
+	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
+		return nil, "", fmt.Errorf("qiyuesuo: http %d", resp.StatusCode)
+	}
+	if contentType == "" {
+		contentType = "image/png"
+	}
+	return data, contentType, nil
+}
+
 func (c *Client) download(path string, query url.Values) ([]byte, error) {
 	u := c.baseURL() + path
 	if len(query) > 0 {

+ 2 - 0
errors.go

@@ -9,6 +9,8 @@ var (
 	ErrInvalidParams = errors.New("qiyuesuo: invalid params")
 	// ErrSealCreatePageUnavailable 制章页面链接未返回(可能未开通接口制章)。
 	ErrSealCreatePageUnavailable = errors.New("qiyuesuo: seal create page unavailable")
+	// ErrSealImageUnavailable 未获取到印章图片。
+	ErrSealImageUnavailable = errors.New("qiyuesuo: seal image unavailable")
 )
 
 type apiResponse struct {

+ 54 - 0
seal.go

@@ -1,6 +1,7 @@
 package qiyuesuosdk
 
 import (
+	"encoding/base64"
 	"strconv"
 	"strings"
 
@@ -9,6 +10,59 @@ import (
 	"git.sxidc.com/student-physical-examination/contract_lock_sdk/model/common"
 )
 
+// DeriveCompanySealName 根据机构名称推导契约锁公章名称(与制章/授权逻辑一致)。
+func DeriveCompanySealName(companyDisplayName string) string {
+	sealName := strings.TrimSpace(companyDisplayName)
+	if sealName == "" {
+		return "机构公章"
+	}
+	if !strings.Contains(sealName, "章") {
+		sealName += "公章"
+	}
+	return sealName
+}
+
+// CompanySealImage 下载机构电子公章图片(PNG)。
+func (c *Client) CompanySealImage(company CompanyLocateParams, sealName string) ([]byte, string, error) {
+	sealName = strings.TrimSpace(sealName)
+	if sealName == "" {
+		return nil, "", ErrInvalidParams
+	}
+	body := map[string]any{
+		"sealName":      sealName,
+		"sealAttribute": "ELECTRONIC",
+		"sealImageFormatRequest": map[string]any{
+			"imageFormat": "png",
+		},
+	}
+	if company.ID != "" {
+		body["companyId"] = company.ID
+	}
+	if company.Name != "" {
+		body["companyName"] = company.Name
+	}
+	if company.RegisterNo != "" {
+		body["registerNo"] = company.RegisterNo
+	}
+	data, contentType, err := c.postForImageBytes("/seal/customparam/image", body)
+	if err != nil {
+		return nil, "", err
+	}
+	if len(data) == 0 {
+		return nil, "", ErrSealImageUnavailable
+	}
+	return data, contentType, nil
+}
+
+// CompanySealImageBase64 下载机构公章并返回标准 Base64(不含 data: 前缀)。
+func (c *Client) CompanySealImageBase64(company CompanyLocateParams, sealName string) (string, string, error) {
+	data, contentType, err := c.CompanySealImage(company, sealName)
+	if err != nil {
+		return "", "", err
+	}
+	return base64.StdEncoding.EncodeToString(data), contentType, nil
+}
+
 // CompanySignQualifications 法人单位签章资质(是否已有可用电子章等)。
 type CompanySignQualifications struct {
 	ElectronicSeal bool `json:"electronicSeal"`