package qiyuesuosdk import ( "encoding/base64" "errors" "strconv" "strings" v2seal_request "git.sxidc.com/student-physical-examination/contract_lock_sdk/model/v2seal/request" v2seal_response "git.sxidc.com/student-physical-examination/contract_lock_sdk/model/v2seal/response" "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 } // CompanySealSummary 法人单位电子印章摘要(来自 /seal/customparam/cert/list)。 type CompanySealSummary struct { ID string Name string Type string SealAttribute string StatusKey string } type sealCertListItem struct { ID string `json:"id"` Name string `json:"name"` Type string `json:"type"` SealAttribute string `json:"sealAttribute"` Status *struct { Key string `json:"key"` } `json:"status"` } type sealCertListResp struct { apiResponse List []sealCertListItem `json:"list"` } // ListCompanyElectronicSeals 查询法人单位下状态正常的电子印章列表。 func (c *Client) ListCompanyElectronicSeals(company CompanyLocateParams) ([]CompanySealSummary, error) { companyReq, err := company.toCompanyRequest() if err != nil { return nil, err } var resp sealCertListResp if err := c.postJSON("/seal/customparam/cert/list", map[string]any{ "companyRequest": companyReq, "sealAttribute": "ELECTRONIC", "sealQueryStatus": "NORMAL", }, &resp); err != nil { return nil, err } if err := resp.err(); err != nil { return nil, err } out := make([]CompanySealSummary, 0, len(resp.List)) for _, item := range resp.List { statusKey := "" if item.Status != nil { statusKey = item.Status.Key } if statusKey != "" && statusKey != "NORMAL" { continue } out = append(out, CompanySealSummary{ ID: item.ID, Name: item.Name, Type: item.Type, SealAttribute: item.SealAttribute, StatusKey: statusKey, }) } return out, nil } func pickCompanySeal(seals []CompanySealSummary, preferredName string) (*CompanySealSummary, error) { if len(seals) == 0 { return nil, ErrSealNotFound } preferredName = strings.TrimSpace(preferredName) if preferredName != "" { for i := range seals { if seals[i].Name == preferredName { return &seals[i], nil } } } for i := range seals { if seals[i].Type == "COMPANY" { return &seals[i], nil } } return &seals[0], nil } // SealImageByID 按印章 id 下载电子章图片。 func (c *Client) SealImageByID(sealID string) ([]byte, string, error) { sealID = strings.TrimSpace(sealID) if sealID == "" { return nil, "", ErrInvalidParams } return c.postForImageBytes("/seal/customparam/image", map[string]any{ "sealId": sealID, "sealAttribute": "ELECTRONIC", "sealImageFormatRequest": map[string]any{ "imageFormat": "png", }, }) } // ResolveCompanySealImageBase64 先列出法人单位电子章,再按 sealId 拉图(避免印章名不一致)。 func (c *Client) ResolveCompanySealImageBase64(company CompanyLocateParams, preferredSealName string) (string, string, string, error) { seals, err := c.ListCompanyElectronicSeals(company) if err != nil { return "", "", "", err } seal, err := pickCompanySeal(seals, preferredSealName) if err != nil { return "", "", "", err } data, contentType, err := c.SealImageByID(seal.ID) if err != nil { return "", "", "", err } if len(data) == 0 { return "", "", "", ErrSealImageUnavailable } return seal.Name, base64.StdEncoding.EncodeToString(data), contentType, nil } // CompanySignQualifications 法人单位签章资质(是否已有可用电子章等)。 type CompanySignQualifications struct { ElectronicSeal bool `json:"electronicSeal"` SM2Cert bool `json:"sm2Cert"` RSACert bool `json:"rsaCert"` } type companySignQualificationsResp struct { apiResponse Result CompanySignQualifications `json:"result"` } type sealCreateResp struct { apiResponse Result v2seal_response.V2SealCreateResponse `json:"result"` } // UserPortalURL 由开放平台 API 地址推导用户前台地址(制章/登录)。 func UserPortalURL(apiAddress string) string { addr := strings.TrimRight(apiAddress, "/") if strings.Contains(addr, ":9182") { return strings.Replace(addr, ":9182", ":9180", 1) } return addr } // CompanySignQualificationsFor 查询法人单位是否具备电子印章等签章资质。 func (c *Client) CompanySignQualificationsFor(company CompanyLocateParams) (*CompanySignQualifications, error) { companyReq, err := company.toCompanyRequest() if err != nil { return nil, err } var resp companySignQualificationsResp if err := c.postJSON("/company/sign/qualifications", map[string]any{ "companyRequest": companyReq, }, &resp); err != nil { return nil, err } if err := resp.err(); err != nil { return nil, err } return &resp.Result, nil } // CompanySealCreatePageURL 获取制作电子公章的页面链接(method=page)。 func (c *Client) CompanySealCreatePageURL(company CompanyLocateParams, companyDisplayName, sealName, operatorMobile string) (string, error) { if sealName == "" || operatorMobile == "" { return "", ErrInvalidParams } displayName := companyDisplayName if displayName == "" { displayName = company.Name } comp := &common.Company{Name: displayName} if company.RegisterNo != "" { comp.RegisterNo = company.RegisterNo } if company.ID != "" { if id, err := strconv.ParseInt(company.ID, 10, 64); err == nil { comp.Id = &id } } modify := true req := v2seal_request.V2SealCreateRequest{ BusinessType: "ELECTRONIC", SealType: "COMPANY", Method: "page", Name: sealName, SealCategoryName: "公章", Company: comp, OperatorInfo: &common.UserInfoRequest{ Mobile: operatorMobile, }, Modify: &modify, } var resp sealCreateResp if err := c.postJSON("/v2/seal/create", req, &resp); err != nil { return "", err } if err := resp.err(); err != nil { return "", err } url := resp.Result.PageUrl if url == "" { url = resp.Result.LocalPageUrl } if url == "" { return "", ErrSealCreatePageUnavailable } return url, nil } // IsSealNotFoundError 静默授权或查章时「查询的印章不存在」。 func IsSealNotFoundError(err error) bool { if err == nil { return false } if errors.Is(err, ErrSealNotFound) { return true } msg := err.Error() return strings.Contains(msg, "查询的印章不存在") || strings.Contains(msg, "无可授权的印章") }