对接方式概述
云银签提供了两种主要的集成方式,以适应不同的业务场景和用户角色:
页面内嵌 (Page Embedding): 将云银签的功能页面(如合同发起、管理列表等)通过 <iframe>
直接嵌入到您的系统中。这种方式主要面向您系统的内部用户(如业务员、管理员),提供无缝的操作体验。需要通过
postMessage 机制进行父子页面的通信。
跳转小程序 (Redirect to Mini-Program):
为您的终端用户(如合同签署方、付款方)生成一个特定的 URL
或二维码。用户点击链接或扫码后,系统会自动判断环境(微信/支付宝),并将其引导至对应的云银签小程序完成后续操作(如签署、查看、支付)。完成后,用户可能会被重定向回您指定的页面。
下面将详细介绍几种常用流程的具体对接方案。
准备工作 (必读)
在开始对接后续的具体业务流程(如发起合同、签署合同等)之前,您必须先获取到后续接口调用所需的关键凭证:accessToken 和
userId。以下是获取这两个凭证的详细步骤:
核心流程示意图
graph TD;
A["第一步:获取应用凭证 (线下向管理员申请)"] --> B(获取 appId 和 appSecret);
B --> C["第二步:调用 /service/getAccessToken (Body 中传入 appId, appSecret)"];
C --> D{获取 accessToken 成功?};
D -- 是 --> E["获得 accessToken 和 corpId"];
D -- 否 --> F["处理错误 (检查 appId/Secret)"];
E --> G["第三步:明确操作者身份 (例如: 业务员张三, 手机号 138...)"];
G --> H["第四步:调用 /member/infoByCorpId (Header : appId, accessToken) (Body:
查询条件如手机号/姓名)"];
H --> I{查询成员信息成功?};
I -- 是 --> J["获得操作者 userId (例如: 20001)"];
I -- 否 --> K["处理错误 (检查查询条件/权限)"];
J --> L["完成准备! 后续接口调用 Header 需携带: appId, accessToken, userId"];
%% 点击事件定义
click C "../api-docs/token/service-token.html#getAccessToken" "查看 获取服务凭证 API 文档"
click H "../api-docs/member/member.html#getMemberInfo" "查看 查询企业成员信息 API 文档"
%% 样式
style E fill:#d4edda,stroke:#155724,stroke-width:2px
style J fill:#d4edda,stroke:#155724,stroke-width:2px
style L fill:#cce5ff,stroke:#004085,stroke-width:2px
style F fill:#f8d7da,stroke:#721c24,stroke-width:1px
style K fill:#f8d7da,stroke:#721c24,stroke-width:1px
步骤详解
第 1 步: 获取应用凭证 (appId & appSecret)
在正式对接前,您的企业需要在云银签平台进行注册和认证。
认证通过后,平台管理员会为您分配一对唯一的应用凭证:appId 和 appSecret。
这两个值是后续所有 API 调用的基础,请务必妥善保管,不要泄露。
如何获取: 请联系贵公司的云银签平台管理员。
第 2 步: 调用 API 获取访问令牌 (accessToken)
使用您获取到的 `appId` 和 `appSecret`,调用 获取服务凭证 API
(`/service/getAccessToken`)。
这是一个 POST 请求,需要将 `appId` 和 `appSecret` 放在请求体 (Request Body) 中。
请求 Body 示例 (JSON):
{
"appId": "您从管理员获取的 appId",
"appSecret": "您从管理员获取的 appSecret"
}
成功响应 Body 示例 (JSON):
{
"code": "200",
"msg": "成功",
"data": {
"accessToken": "生成的访问令牌字符串 (例如: 7eb5d4a7-...) ",
"corpId": 10001, // 您企业在云银签的 ID
"expiresIn": 1718888888000 // 令牌过期时间戳 (毫秒)
}
}
您需要从响应的 `data` 中提取并保存 accessToken。请注意
expiresIn,令牌会在指定时间后失效,需要重新获取。
第 3 步: 理解并获取操作者用户 ID (userId)
userId 代表了**在您的系统中实际执行操作的用户**。例如,如果是租房
App,发起租房合同的可能是某个房产中介(张三)。这个"张三"需要在云银签系统中被添加为贵企业(租房 App 公司)的成员,并获得一个唯一的 `userId`。
如何添加成员? 通常由企业管理员在云银签管理后台操作,或者通过调用人员管理相关 API 添加。
在进行具体操作(如发起合同)前,您需要知道是**哪个 `userId`** 在执行这个操作。
您可以通过调用 查询企业成员信息 API
(`/member/infoByCorpId`) 来查找特定用户的 `userId`。
**【关键】调用此 API 时:**
必须在请求的 **Header** 中携带 appId 和上一步获取的 accessToken。
可以在请求 Body 中传入查询条件,例如用户的手机号或姓名,来精确查找。
请求 Header 示例:
appId: 您企业的 appId
accessToken: 您获取到的 accessToken
请求 Body 示例 (查询手机号为 138... 的用户):
{
"mobile": "13800138000"
}
成功响应 Body 示例 (JSON):
{
"code": "200",
"msg": "成功",
"data": [ // 可能返回多个,如果查询条件不唯一
{
"userId": 20001, // 这就是您需要的操作者 userId
"userName": "张三",
"mobile": "13800138000",
"userStatus": 0, // 0:有效
"realName": "张三",
"realNameStatus": 1 // 1:已实名
}
// ... 其他可能匹配的用户 ...
]
}
从返回的 `data` 数组中找到您需要的用户,并获取其 userId。
第 4 步: 后续接口调用
在完成以上步骤,成功获取到有效的 accessToken 和具体操作者的 userId
后,您就可以调用其他业务接口了(如发起合同、查询合同等)。
【非常重要】 调用后续所有需要授权的业务接口时,**必须** 在请求的 **Header** 中统一携带以下三个参数:
appId
accessToken
userId (当前操作者的 ID)
后续请求 Header 示例:
appId: 您企业的 appId
accessToken: 您获取到的 accessToken
userId: 20001
普通发起合同 (页面内嵌)
此方案适用于需要由您系统的内部用户(如业务员)直接上传文件、填写参与方并发起非模板化合同的场景。发起页面将通过 iframe 嵌入到您的系统中。
前提: 请确保您已完成 准备工作 中的步骤,获取了有效的 accessToken
和当前操作用户的 userId。
流程示意图
graph TD;
subgraph DevSystemFE ["开发者系统前端"]
A[用户点击 发起合同 按钮] --> B[构建内嵌页面 URL];
B -- 携带 accessToken, userId, source --> C["嵌入 iframe (显示 initiat.png)"];
D[监听来自 iframe 的 postMessage];
G --> D;
D --> H{收到成功/失败/取消消息?};
H -- 成功 --> I["处理成功逻辑 (提示/跳转)"];
H -- 其他 --> J[处理失败/取消逻辑];
end
subgraph 云银签Iframe ["云银签内嵌页面iframe"]
C --> E["用户操作 (上传/添加/填写/发起)"];
E --> F(操作完成/取消);
F --> G(通过 postMessage 通知父页面);
end
%% Restored click definitions
click B "#direct-initiation-embed-step1" "查看构建URL步骤"
click C "#direct-initiation-embed-step2" "查看嵌入iframe步骤"
click D "#direct-initiation-embed-step3" "查看监听消息步骤"
click G "#direct-initiation-embed-step3" "查看监听消息步骤"
%% Testing style definitions one by one - RESTORED
style B fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style C fill:#fffbe6,stroke:#faad14,stroke-width:2px,color:#333
style D fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style G fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
对接方式
页面内嵌 (<iframe>)
步骤详解
第 1 步 (原第 2 步): 构建内嵌页面的 URL
基础 URL: https://open.yunyinsign.com/h5/pages/uploadInitiation/index
需要拼接的参数 (Query String):
appId: (必填) 准备工作中获取的appId。
accessToken: (必填) 准备工作中获取的有效访问令牌。
userId: (必填) 准备工作中获取并映射好的当前操作用户的云银签 `userId`。
URL 示例:
https://open.yunyinsign.com/h5/pages/uploadInitiation/index?accessToken=your_unique_access_token_string&userId=20001&source=mySystem
第 2 步 (原第 3 步): 在您的页面中嵌入 iframe
在您系统需要发起合同的页面上,使用 HTML 的 <iframe> 标签,将 src 属性设置为上一步构建的
URL。
嵌入后,用户将看到类似下图的云银签发起合同页面,其中第一个签署方(通常是发起人)信息可能会根据传入的 `userId` 自动填充:
截图示例: 普通发起合同
示例代码:
<iframe
id="yyq-initiate-iframe"
src="构建好的URL放在这里"
width="100%"
height="800px" /* 根据需要调整高度 */
frameborder="0">
</iframe>
第 3 步 (原第 4 步): 监听内嵌页面的消息 (postMessage)
内嵌页面在用户完成操作(如发起成功、取消、失败)时,会通过 window.parent.postMessage() 向您的父页面发送消息。
您需要在父页面添加事件监听器来接收这些消息,并根据消息内容进行后续处理。
示例 JavaScript 代码和消息体结构可参考本文档其他内嵌流程的说明,或根据云银签提供的具体规范进行调整(例如,消息 `type` 可能为
`yyq.initiate.direct.result`)。
成功消息通常会包含新创建的合同流程 ID (`signFlowId`)。
注意事项
内嵌页面的具体 URL 需要由云银签提供或在相关文档中查找。
请确保内嵌页面的域名已被添加到浏览器的可信来源中,以便 postMessage 正常工作。
accessToken 的有效期需要关注,如果过期,内嵌页面可能无法加载或操作失败。
模板发起合同 (页面内嵌)
前提: 请确保您已完成 准备工作 中的步骤,获取了有效的 accessToken
和当前操作用户的 userId。
此方案适用于需要由内部用户(如业务员)先从系统中选择一个已创建好的合同模板,然后通过内嵌的云银签页面填写模板变量并发起合同的场景。
核心流程概览
在用户选择模板并发起之前,您的系统可能需要先管理这些模板。云银签提供了完整的模板管理 API,包括:
您可以根据需要调用这些 API 来维护您系统中的模板库。以下流程图展示了从选择模板到通过内嵌页面发起合同的交互过程:
graph TD;
subgraph "开发者系统(后台/前端)"
A["准备/管理模板 (增/改/查/启停用等)"] --> B("调用 API: /template/list");
B --> C{"获取模板列表成功?"};
C -- 是 --> D["前端展示模板列表 (见截图: 模板列表)"];
C -- 否 --> E["处理错误"];
D --> F("用户选择模板");
F --> G["构建内嵌页面 URL (含 templateId, token 等)"];
G --> H["嵌入 iframe 显示发起页面 (见截图: 模板发起)"];
I["监听来自 iframe 的 postMessage"];
end
subgraph "云银签内嵌页面 (iframe)"
H --> J("用户填写信息 & 发起签署");
J --> K("操作完成/取消");
K --> L("通过 postMessage 通知父页面");
end
subgraph "开发者系统(前端)"
L --> I;
I --> M{"收到成功/失败/取消消息?"};
M -- 成功 --> N["处理成功逻辑 (如:提示发起成功, 刷新状态)"];
M -- 其他 --> O["处理失败/取消逻辑"];
end
%% 点击事件定义
click A "../api-docs/template/template.html" "查看模板管理API"
click B "../api-docs/template/template.html#templateList" "查看模板列表API"
click G "#template-initiation-embed-step2" "查看构建URL步骤"
click H "#template-initiation-embed-step3" "查看嵌入iframe步骤"
click I "#template-initiation-embed-step4" "查看监听消息步骤"
click L "#template-initiation-embed-step4" "查看监听消息步骤"
%% 添加样式突出显示可点击节点
%% style A fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style B fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style G fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style H fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style I fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style L fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
对接方式
页面内嵌 (<iframe>)
步骤详解
第 1 步: (准备) 获取模板列表并在您的系统中展示
您的后端服务调用 模板列表查询 API
(`/template/list`) 获取当前企业可用(通常是已启用)的模板列表。
您的前端页面根据 API 返回的数据,渲染一个模板选择界面,如下图所示:
截图: 模板列表
用户在此界面选择一个想要使用的模板。您需要获取用户选择的模板 `templateId`。
确保已获取有效的 `accessToken` (参见 获取服务凭证 API )。
需要准备发起人对应的和 `userId`。
第 2 步: 构建内嵌页面的 URL
基础 URL: `https://open.yunyinsign.com/h5/pages/home/InitiateContract/components/detail`
需要拼接的参数 (Query String):
`appId`: (必填) 基础应用ID。
`accessToken`: (必填) 获取到的访问令牌。
`userId`: (必填) 发起人用户 ID。
`templateId`: (必填) 用户在第 1 步选择的模板 ID。
URL 示例:
https://open.yunyinsign.com/h5/pages/home/InitiateContract/components/detail?accessToken=YOUR_TOKEN&userId=20001&templateId=TPL001&source=mySystem
第 3 步: 在您的页面中嵌入 iframe
使用 HTML 的 <iframe> 标签,将 src 属性设置为上一步构建的 URL。
嵌入后,用户将看到类似下图的云银签模板发起页面:
截图: 模板发起
示例代码:
<iframe id="yyq-template-initiate-iframe" src="构建好的URL放在这里" width="100%" height="800px" frameborder="0"></iframe>
第 4 步: 监听内嵌页面的消息 (postMessage)
内嵌页面在用户完成操作(如发起成功、取消)时,会通过 `window.parent.postMessage()` 向您的父页面发送消息。
您需要在父页面添加事件监听器来接收这些消息,并根据消息内容(如 `status`, `data.signFlowId`, `error`)进行后续处理。
示例 JavaScript 代码和消息体结构,请参考 普通发起合同 (内嵌) 流程的第 4
步说明(消息类型 `type` 可能为 `yyq.initiate.template.result`,具体请与后端确认)。
注意事项
如果模板包含需要预填的组件(如发起人信息),可以在构建 URL 时将这些信息作为参数传递给内嵌页面,以减少用户手动输入(具体参数需确认)。
`accessToken` 的有效期需要关注,如果过期,内嵌页面可能无法加载或操作失败。
发起方签署/填写 (页面内嵌)
前提:
合同已通过 普通发起 或 模板发起 流程创建。
请确保您已完成 准备工作 中的步骤,获取了有效的 accessToken
和当前登录系统的操作用户(即发起方成员)的 userId。
您需要知道当前操作用户所属的企业的 openCorpId。
此方案适用于合同发起后,需要由发起方(您系统的内部用户)在您的系统内继续完成查看、填写或签署合同信息的场景。
核心流程示意图
graph TD;
subgraph "发起方处理流程"
A["用户登录系统 (发起方员工)"] --> B["调用 API 获取企业合同列表 (/signTask/enterpriseContracts/list)Header : appId, accessToken, userId (操作人), openCorpId (企业ID)"];
B --> C{获取列表成功? 获取 flowId, operateStatus, directFlag 等};
C -- 是 --> D["前端根据 operateStatus 展示合同列表及对应操作按钮 (如: 查看, 去填写, 去签署)"];
C -- 否 --> E["处理错误"];
D --> F["用户点击操作按钮"];
F --> G["获取合同 flowId 及其他必要信息"];
G --> H["根据 operateStatus 和 directFlag 构建特定的H5内嵌页面 URL"];
H --> I["嵌入 iframe 显示H5处理页面 (查看/填写/签署页)"];
I --> K("用户完成操作");
K --> L("操作完成/取消");
L --> M("通过 postMessage 通知父页面");
M --> J["监听来自 iframe 的 postMessage"];
J --> N{"收到成功/失败/取消消息?"};
N -- 成功 --> O["处理成功逻辑 (如:刷新列表, 提示成功)"];
N -- 其他 --> P["处理失败/取消逻辑"];
end
click B "../api-docs/signtask/query.html#getEnterpriseContractList" "查看企业合同列表API"
click D "showImage:my-contact.png" "点击查看截图: 我的合同 (示意图)"
click H "#initiator-action-embed-step2" "查看构建URL步骤"
click I "#initiator-action-embed-step3" "查看嵌入iframe步骤"
click J "#initiator-action-embed-step4" "查看监听消息步骤"
click M "#initiator-action-embed-step4" "查看监听消息步骤"
style B fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style H fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style I fill:#fffbe6,stroke:#faad14,stroke-width:2px,color:#333
style J fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style D fill:#fffbe6,stroke:#faad14,stroke-width:2px,color:#333
style M fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
对接方式
页面内嵌 (<iframe>),内嵌页面为H5页面。
步骤详解
第 1 步: 获取并展示企业合同列表及操作状态
当发起方用户登录您的系统后,您的后端服务需要调用 企业合同列表 API (`/signTask/enterpriseContracts/list`)。
**重要:** 调用此 API 时,必须在 **Header** 中传入:
appId: 您的应用ID。
accessToken: 当前登录用户的有效访问令牌。
userId: 当前登录用户的 `userId`。
openCorpId: 当前登录用户所属企业的ID。
API 会返回该企业相关的合同列表。对于每份合同,您需要关注以下关键字段(通常在返回的 `data` 数组的每个对象中):
flowId: 合同流程ID。
flowStatus: 整体流程状态。
operateStatus: 当前用户(即Header中传入的`userId`)对该合同的操作状态。例如:1-填写, 2-签署, 4-查看等。这是判断应显示何种操作按钮的关键。
directFlag: 是否直发(0-否, 1-是)。当 `operateStatus` 为签署时,此字段用于区分使用哪个签署页面。
其他合同基本信息如 flowTitle(合同标题)等。
您的前端页面根据返回的数据,渲染一个合同列表。针对列表中的每一份合同,根据其 operateStatus,为当前用户显示相应的操作按钮。例如:
如果 operateStatus 指示"待查看",则显示"查看合同"按钮。
如果 operateStatus 指示"待填写",则显示"去填写"按钮。
如果 operateStatus 指示"待签署",则显示"去签署"按钮。
参考截图:
截图示意: 合同列表 (按钮根据状态动态生成)
第 2 步: 根据操作类型构建特定的H5内嵌页面 URL
当用户点击具体的操作按钮(如"查看合同"、"去填写"、"去签署")时,您已经获取了该合同的 flowId 以及相关的 operateStatus 和 directFlag。
您需要根据这些信息,选择并构建以下四种H5内嵌页面的URL之一。所有H5内嵌页面都需要以下通用参数,请通过Query String传递:
appId: (必填) 您的应用ID。
accessToken: (必填) 当前登录用户的有效访问令牌。
userId: (必填) 当前登录用户的 `userId`。
flowId: (必填) 当前操作的合同流程ID。
URL构建逻辑:
如果操作是"查看合同" (假设 operateStatus 对应查看):
基础 URL: https://open.yunyinsign.com/h5/pages/myActivities/lookOver/
示例 URL: https://open.yunyinsign.com/h5/pages/myActivities/lookOver/?appId=YOUR_APPID&accessToken=YOUR_TOKEN&userId=USER_ID&flowId=FLOW_ID
如果操作是"去填写" (假设 operateStatus 对应填写):
基础 URL: https://open.yunyinsign.com/h5/pages/myActivities/signingPage (此页面用于填写)
示例 URL: https://open.yunyinsign.com/h5/pages/myActivities/signingPage?appId=YOUR_APPID&accessToken=YOUR_TOKEN&userId=USER_ID&flowId=FLOW_ID
如果操作是"去签署" (假设 operateStatus 对应签署):
此时需要判断 directFlag:
如果 directFlag 为 1 (直发):
基础 URL: https://open.yunyinsign.com/h5/pages/myActivities/directInitiation
示例 URL: https://open.yunyinsign.com/h5/pages/myActivities/directInitiation?appId=YOUR_APPID&accessToken=YOUR_TOKEN&userId=USER_ID&flowId=FLOW_ID
如果 directFlag 为 0 (非直发):
基础 URL: https://open.yunyinsign.com/h5/pages/myActivities/fillout
示例 URL: https://open.yunyinsign.com/h5/pages/myActivities/fillout?appId=YOUR_APPID&accessToken=YOUR_TOKEN&userId=USER_ID&flowId=FLOW_ID
第 3 步: 在您的页面中嵌入 iframe (加载H5页面)
使用 HTML 的 <iframe> 标签,将 src 属性设置为上一步根据逻辑构建好的特定H5页面 URL。
用户将在iframe中看到对应的云银签H5页面(查看、填写或特定类型的签署页面)。
以下是填写和签署页面的H5界面截图示例:
示例:H5合同填写页面 (对应 .../signingPage)
示例:H5合同签署页面 (对应 .../fillout 或 .../directInitiation)
示例代码:
<iframe id="yyq-h5-task-iframe" src="构建好的特定H5页面URL放在这里" width="100%" height="800px" frameborder="0"></iframe>
第 4 步: 监听内嵌H5页面的消息 (postMessage)
内嵌的H5页面在用户完成操作(查看完毕可能无消息,填写/签署成功、取消等)时,会通过 window.parent.postMessage() 向您的父页面发送消息。
您需要在父页面添加事件监听器来接收这些消息。请参考 可内嵌页面参考 章节中关于 H5 端 `postMessage` 的详细说明,特别是监听 event.data.type 可能的值,如:
goBack: 返回上一层页面。
contract: 返回合同列表页。
goShare: 返回分享页面。
message: 一般性消息,常用于报错提示 (例如:Token过期,具体消息在 event.data.message)。
根据接收到的消息类型和内容,进行相应的处理,例如关闭iframe、刷新合同列表、给出用户提示等。
注意事项
请务必使用正确的 operateStatus 值来判断应展示的操作和构建的URL。该状态值的具体含义请参照 `/signTask/enterpriseContracts/list` 接口的文档。
所有H5内嵌页面的基础域名请以云银签实际提供为准。
确保在调用企业合同列表 API 和构建内嵌 URL 时,使用的 `accessToken` 和 `userId` 是**当前登录的发起方员工**的凭证,且`openCorpId`是其所属企业。
关注 `accessToken` 的有效期。
重要提示: 发起方完成操作后,根据企业配置,合同可能进入"待审批"状态,需要等待内部审批人处理后才能流转至下一方。请参考
合同审批 (API 对接) 章节。
合同审批 (API 对接)
适用场景: 对于需要内部审核流程的企业,例如确保合同内容合规、控制重要印章(如公章)的使用权限等,可以在合同流转过程中加入此审批环节。
流程位置: 通常发生在合同发起方完成其签署/填写操作之后,在合同流向其他外部签署方或支付方之前。
实现方式: 此功能**完全通过 API 对接**,需要在开发者自己的业务系统(例如租房 App
的管理后台)中为具有审批权限的用户(如管理员、法人)构建审批管理界面。
前提:
审批人已在云银签系统中注册并完成实名认证(设置了签署密码)。
审批流程已在云银签平台或通过 API 配置(具体配置方式请参考相关文档或联系技术支持)。
您已完成 准备工作 ,能获取到有效的 accessToken 以及**审批人**的
userId。
核心流程示意图 (开发者系统内实现)
graph TD;
subgraph ClientSystem ["开发者系统 (审批管理界面)"]
A[审批人登录系统] --> B["调用 API 获取 待审批列表 (/signTask/getApprovalList, docQueryType=0) Header:
appId, accessToken, 审批人userId"];
B --> C{获取列表成功?};
C -- 是 --> D["展示待审批合同列表 (需显示合同名称, 发起人, 审批ID等)"];
C -- 否 --> E[处理错误];
D --> F["审批人选择合同 (获取 approvalId)"];
F --> G{选择操作: 通过/驳回};
G -- 通过 --> H["调用'审批通过' API (/signTask/approvalSign, status=2) Header: appId, accessToken,
审批人userId Body: approvalId, approvalStatus=2 可能需验证审批人签署密码"];
G -- 驳回 --> I["调用'审批驳回' API (/signTask/approvalCancel, status=3) Header: appId,
accessToken, 审批人userId Body: approvalId, approvalStatus=3, failReason"];
H --> J{审批API调用成功?};
I --> J;
J -- 是 --> K[系统内更新合同状态, 通知相关方];
J -- 否 --> L[处理API错误];
end
subgraph NextSteps ["后续流程"]
M["审批通过: 合同进入下一环节 (如: 等待外部用户签署/支付)"];
N["审批驳回: 合同流程中止/退回发起人"];
end
ClientSystem --> NextSteps;
%% API Links (Keep as is)
click B "../api-docs/signtask/获取审批管理列表_OpenAPI.json" "查看 获取审批列表 API 文档"
click H "../api-docs/signtask/审批合同用章_OpenAPI.json" "查看 审批通过 API 文档"
click I "../api-docs/signtask/撤销审批合同用章_OpenAPI.json" "查看 审批驳回 API 文档"
%% Styles (Keep as is)
style B fill:#e6f7ff,stroke:#096dd9,stroke-width:2px
style H fill:#d4edda,stroke:#155724,stroke-width:2px
style I fill:#f8d7da,stroke:#721c24,stroke-width:2px
style K fill:#cce5ff,stroke:#004085,stroke-width:2px
步骤详解
第 1 步: 构建审批人工作台
在您的业务系统中,为指定的审批角色(管理员、法人等)创建一个"审批管理"或"待我审批"的页面。
审批人登录系统后,访问此页面。
第 2 步: 调用 API 获取待审批列表
您的后端服务调用 获取审批管理列表
API (`/signTask/getApprovalList`)。
**重要:**
请求 **Header** 中必须携带 `appId`, `accessToken` 和 **当前登录审批人的 `userId`**。
请求 **Body** 中设置 `docQueryType` 为 `0` (表示查询"待我审批")。可以根据需要添加其他筛选条件(如发起时间范围、合同名称等)。
请求 Body 示例 (查询待我审批):
{
"docQueryType": 0,
"listPageNo": 1,
"listPageSize": 10
}
API 会返回该审批人名下待处理的审批任务列表。您需要解析响应数据,特别是获取每条记录的 `approvalId` (审批申请ID) 和相关的合同信息(如
`signFlowName`, `initiatorName`, `createTime` 等)。
成功响应 Body 示例 (部分字段):
{
"code": "200",
"msg": "成功",
"data": [
{
"approvalId": 987654321, // 审批申请ID (非常重要)
"approvalCode": "APV20240521001",
"approvalName": "市场部合同用章审批",
"signFlowId": 123456789,
"signFlowName": "汽车租赁合同testtt",
"approvalType": 1, // 1: 合同用章审批
"approvalStatus": 1, // 1: 审批中 (待当前审批人处理)
"initiatorName": "梁运和",
"createTime": "2024-05-21T10:00:00"
// ... 其他字段 ...
}
// ... more approval tasks ...
]
}
在前端页面展示这个列表,并为每条记录提供"通过"和"驳回"的操作按钮。
第 3 步: 调用 API 执行审批操作
审批通过:
当审批人点击"通过"时,您的后端调用 审批通过 API (`/signTask/approvalSign`)。
请求 **Header**:`appId`, `accessToken`, **审批人的 `userId`**。
请求 **Body**:必须包含 `approvalId` (从列表获取) 和 `approvalStatus` 设置为 `2`。
请求 Body 示例:
{
"approvalId": 987654321,
"approvalStatus": 2
}
注意:
此接口**可能**会触发验证审批人的签署密码(取决于系统安全设置),如果验证失败会返回错误。请确保审批人在个人认证时已设置签署密码 (参考 个人认证更新
API )。
审批驳回:
当审批人点击"驳回"时,您的后端调用 审批驳回 API (`/signTask/approvalCancel`)。(注意:API 名字是
`approvalCancel`,但实际用于驳回场景)
请求 **Header**:`appId`, `accessToken`, **审批人的 `userId`**。
请求 **Body**:必须包含 `approvalId` 和 `approvalStatus` 设置为 `3`。建议同时提供 `failReason`
(驳回原因) 方便发起人了解情况。
请求 Body 示例:
{
"approvalId": 987654321,
"approvalStatus": 3,
"failReason": "合同金额与条款不符,请修改后重新提交。"
}
处理 API 的响应结果,如果成功,则刷新审批列表或更新界面状态。
第 4 步: 处理审批结果
审批通过后: 合同会自动流转到下一个需要操作的参与方(例如,外部签署人)。您可以引导这些用户按 合同签署/支付 (跳转小程序) 流程操作。
审批驳回后:
合同流程通常会中止,状态变为"已驳回"。您需要根据业务逻辑决定如何通知发起人(例如,站内信、短信)以及是否允许发起人修改后重新提交审批。
注意事项
审批人的 `userId` 获取方式与普通员工类似,通过 查询企业成员信息 API 获取。
企业可能存在多级审批或会签等复杂流程,此处的 API 主要针对单节点审批场景。如需更复杂的审批流配置,请查阅详细的审批配置文档或联系技术支持。
确保审批人已完成实名认证并设置了签署密码,否则"审批通过"操作可能失败。
【重要】自动跳过审批:
如果合同是由配置好的审批人(例如管理员、法人)本人直接发起的,系统会自动跳过该审批环节,合同将直接流转至下一环节(如等待外部用户签署/支付)。
合同签署/支付 (跳转小程序)
前提:
合同已完成所有前置步骤,包括发起方的操作以及必要的内部审批(如果配置了审批流程,合同状态需为"审批通过"或直接进入签署环节)。
请确保您已完成 准备工作 中的步骤,获取了有效的 accessToken。
您需要能获取到目标操作用户(签署人/支付人)的 participantId (通常从合同详情或列表 API 中获取)。
核心流程概览
这个流程通常发生在合同已经对用户可见之后。开发者系统需要先获取用户的合同列表,然后为待处理的合同生成跳转小程序的入口。以下是主要步骤:
graph TD;
subgraph "开发者系统 (后台/前端)"
AA["合同已发起 (通过内嵌等方式)"] --> A["调用 API 获取 指定用户的合同列表"];
A --> B{"获取列表成功?"};
B -- 是 --> C["前端展示合同列表 (类似 my-contact.png)"];
B -- 否 --> D["处理错误"];
C --> E["用户选择合同 并点击 签署/支付/分享"];
E --> F["调用 API 获取跳转 URL"];
F -- "请求参数: flowId, participantId, source(wx/alipay), redirectUrl, extParam" --> G{"获取 URL
成功?"};
G -- 是 --> H["生成按钮链接或二维码 (类似 share-contact.png)"];
G -- 否 --> I["处理错误"];
J["在 redirectUrl 页面 监听回调参数"];
end
subgraph "终端用户 (App/H5/扫码)"
H --> K["点击链接 / 扫描二维码"];
end
subgraph "云银签系统 (后端/中间页)"
K --> L["接收请求, 判断环境 根据 source 重定向"];
end
subgraph "云银签小程序 (微信/支付宝)"
L --> M["加载签署/支付任务 (类似 xcx.png)"];
M --> N["用户完成操作"];
N --> O["操作完成/取消/失败"];
O --> P["携带结果参数 跳转回 redirectUrl"];
end
subgraph "开发者系统 (前端回调页)"
P --> J;
J --> Q{"解析回调参数 (status, extParam...)"};
Q --> R["向用户展示结果建议后端再查询确认状态 "];
end
%% 点击事件定义
click A "#signing-payment-redirect-step1" "查看获取列表说明"
click F "#signing-payment-redirect-step2" "查看获取URL说明"
click H "#signing-payment-redirect-step3" "查看提供入口说明"
click J "#signing-payment-redirect-step4" "查看处理回调说明"
click R "#signing-payment-redirect-step4" "查看处理回调说明"
%% 特殊点击定义,用于触发图片弹窗 (使用特殊前缀)
click C "showImage:my-contact.png" "点击查看截图: 我的合同"
click H "showImage:share-contact.png" "点击查看截图: 分享合同"
click M "showImage:xcx.png" "点击查看截图: 小程序签署邀请页"
%% 添加样式
style A fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style F fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
style J fill:#e6f7ff,stroke:#096dd9,stroke-width:2px,color:#333
%% 为可查看图片的节点添加不同样式 (例如,不同的边框或图标)
style C fill:#fffbe6,stroke:#faad14,stroke-width:2px,color:#333
style H fill:#e6f7ff,stroke:#faad14,stroke-width:2px,color:#333
style M fill:#fffbe6,stroke:#faad14,stroke-width:2px,color:#333
对接方式
跳转小程序 (URL / 二维码)
步骤详解
第 1 步: (准备) 获取用户合同列表
您的系统需要先调用一个 API /contract/listByUserPhone,传入终端用户的手机号,获取该用户相关的合同列表。
API 应返回包含合同基本信息(名称、状态等)、流程 ID (`flowId`) 以及每个待处理签署方/支付方的参与者 ID (`participantId`) 的数据。
您的 App 或 H5 页面根据返回的数据,渲染一个合同列表界面供用户查看,类似下图:
截图示例: 我的合同
第 2 步: (核心) 调用 API 获取跳转 URL
当用户需要对某份合同进行签署或支付时,您的系统需要调用一个 API /signTask/contract/appletForParticipantUrl 来获取跳转到云银签小程序的 URL。
调用此 API 需要传递以下核心参数:
participantId: (必填) 具体操作的签署方或支付方的参与者 ID。
type: (推荐) 指定目标小程序,传 wx 或
alipay。如果您的入口明确区分微信/支付宝(如不同按钮),请务必传递此参数。若不传,云银签会尝试自动判断或默认微信。
redirectUrl: (必填) 用户在小程序完成操作后,云银签将携带结果参数跳转回的目标 H5 页面 URL。**此 URL
必须是公网可访问的,并且需要进行 URL Encode 编码**。
extParam: (可选) 开发者自定义的扩展参数,例如订单号、用户标识等。云银签会在回调时原样带回。**此参数也需要进行 URL
Encode 编码**。
API 成功调用后,会返回一个可以直接使用的跳转 URL。
微信短链接或支付宝拼接地址,前端直接window.open即可
第 3 步: 在您的应用中提供入口 (链接或二维码)
**按钮/链接:** 将上一步获取到的 URL 直接设置为操作按钮(如"立即签署"、"去支付"、"分享签署链接")的点击跳转目标。
**二维码:** 如果需要提供扫码入口(例如分享给他人签署),使用您系统熟悉的前端或后端二维码生成库,将上一步获取到的 URL 生成二维码图片展示给用户。类似下图:
截图示例: 分享合同
第 4 步: 处理回调 (在您的 redirectUrl
页面)
用户点击链接或扫码后,会被引导至云银签小程序完成操作。完成后,小程序会跳转回您在第 2 步提供的 redirectUrl。
跳转时,云银签会在 URL Query String 中附加结果参数。您需要在 redirectUrl 对应的 H5 页面中,使用
JavaScript 解析这些参数。
关键回调参数示例 (具体参数名需与后端确认):
// 成功示例 (签署+支付)
https://yourapp.com/callback?flowId=FLOW789&participantId=PART123&status=success&signStatus=signed&payStatus=paid&orderNo=PAYORDER001&extParam=YOUR_ENCODED_PARAM
// 仅签署成功示例
https://yourapp.com/callback?flowId=FLOW789&participantId=PART123&status=success&signStatus=signed&extParam=YOUR_ENCODED_PARAM
// 用户取消示例
https://yourapp.com/callback?flowId=FLOW789&participantId=PART123&status=cancel&extParam=YOUR_ENCODED_PARAM
// 失败示例
https://yourapp.com/callback?flowId=FLOW789&participantId=PART123&status=fail&errorCode=SIGN_FAIL&errorMessage=签名验证失败&extParam=YOUR_ENCODED_PARAM
您的回调页面需要:
解析 URL 获取 status, signStatus, payStatus,
errorCode, extParam (解码后使用) 等参数。
根据参数向用户展示清晰的操作结果(成功、失败原因、取消等)。
**【重要建议】** 前端收到的回调仅用于即时展示。为确保数据最终一致性,您的**后端服务应该根据收到的 `flowId` (或从 `extParam`
解码出的业务单号),再次调用云银签的合同状态查询 API,获取最准确、最权威的合同状态,并更新您自己系统的业务状态。**
用户进入小程序后看到的界面可能类似下图,后续流程由云银签小程序引导:
截图示例: 小程序签署邀请页
注意事项
`redirectUrl` 和 `extParam` 在传入获取跳转 URL 的 API 时,**必须进行 URL Encode 编码**。
`redirectUrl` 必须是公网可访问的 H5 页面地址。
请务必做好前端回调参数的解析和后端状态的最终确认。
可内嵌页面参考
本章节详细列出了云银签系统提供的、可内嵌至您自有系统中的PC端和H5端页面,包括所需的跳转参数及与内嵌页面通信的方式。请注意,所有内嵌页面的域名均以 https://open.yunyinsign.com为准。
PC 端页面
H5 端页面
PC 端可内嵌页面
以下是PC端可以内嵌的页面及其说明。请确保您已参照 准备工作 获取了必要的 appId 和 token (即 accessToken)。
1. 目录结构 (可内嵌页面URL)
http://open.yunyinsign.com/#/personalCertificate - 个人认证页面
http://open.yunyinsign.com/#/companyCertification - 企业认证第一步页面 (企业认证只需要接入第一步的页面)
http://open.yunyinsign.com/#/companyCertificationTwo - 企业认证第二步页面
http://open.yunyinsign.com/#/editTemplates - 新增模板 (组件操作页面从新增过去的不需要单独接入)
http://open.yunyinsign.com/#/settingTemplate - 控件操作
http://open.yunyinsign.com/#/designatedSignature - 直接发起指定签署位置 (控件操作)
http://open.yunyinsign.com/#/signingPage - 合同填写页面
http://open.yunyinsign.com/#/fillout - 合同签署盖章页面 (和直接发起指定签署位置的页面)
http://open.yunyinsign.com/#/directInitiation - 直接发起不指定位置的合同盖章页面
http://open.yunyinsign.com/#/lookOver - 合同查看页面
http://open.yunyinsign.com/#/controlStamping - 印章列表 (个人和公司)
http://open.yunyinsign.com/#/personalSeal - 新增印章 (个人)
http://open.yunyinsign.com/#/corporate - 新增印章 (公司印章)
http://open.yunyinsign.com/#/sealDetail - 印章详情和授权 (公司印章)
2. 页面跳转参数详情
注意: 参数名 token 在此上下文中通常指代 accessToken。
2.1 个人认证页面 (personalCertificate)
参数名 是否必传 参数说明
appId 是 应用ID
token 是 登录标识 (accessToken)
userId 是 用户需要绑定的用户ID
2.2 企业认证第一步页面 (companyCertification)
参数名 是否必传 参数说明
appId 是 应用ID
token 是 登录标识 (accessToken)
userId 是 用户需要绑定的用户ID
corpId 是 企业ID
corpName 否 企业名称
2.3 新增/编辑模板页面 (editTemplates)
参数名 是否必传 参数说明 id参数说明
appId 是 应用ID 根据templateType决定: 0: 新增模版 - 不用传 1: 设置模版 - 必须传 2: 使用模版 - 必须传 3: 直接发起 - 不用传
token 是 登录标识 (accessToken)
userId 是 用户需要绑定的用户ID
corpId 是 企业ID
templateType 是 0: 新增模版 | 1: 设置模版 | 2: 使用模版 | 3: 直接发起
id 见右侧 模板ID
2.4 合同处理系列页面 (signingPage, fillout, directInitiation, lookOver)
参数名 是否必传 参数说明
appId 是 应用ID
token 是 登录标识 (accessToken)
userId 是 用户需要绑定的用户ID
corpId 是 企业ID
id 是 合同ID (对应您其他文档中的 flowId)
3. 与PC内嵌页面通信 (postMessage)
父页面可以通过以下方式监听来自PC内嵌iframe的消息:
window.addEventListener('message', (e) => {
if (e.origin !== 'https://open.yunyinsign.com') { // 校验来源, open.yunyinsign.com 替换为实际域名
// return; // 生产环境建议开启来源校验
}
console.log('iframe数据', e.data); // e.data 通常是一个对象
if (e.data && typeof e.data === 'object' && e.data.type) {
console.log('事件类型:', e.data.type);
// 根据 e.data.type 处理不同事件
// 例如: if (e.data.type === 'goBack')
// if (e.data.type === 'succeed')
}
});
PC内嵌页面可能抛出的 e.data.type 值及其说明:
接受值的参数名 (e.data.type) 参数说明
goBack 返回上一层的标识
succeed 事件执行成功的返回
H5 端可内嵌页面
以下是H5端(通常用于移动应用内嵌WebView或手机浏览器)可以内嵌的页面及其说明。请确保您已参照 准备工作 获取了必要的 appId 和 accessToken。
1. 目录结构 (可内嵌页面URL)
https://open.yunyinsign.com/h5/pages/user/personal/Certification - 个人实名认证
https://open.yunyinsign.com/h5/pages/uploadInitiation/index - 发起合同
https://open.yunyinsign.com/h5/pages/home/InitiateContract/components/detail - 模板发起合同
https://open.yunyinsign.com/h5/pages/myActivities/lookOver/ - 合同查看页面
https://open.yunyinsign.com/h5/pages/myActivities/signingPage - 合同填写页面
https://open.yunyinsign.com/h5/pages/myActivities/fillout - 合同控件签署页面
https://open.yunyinsign.com/h5/pages/myActivities/directInitiation?flowId=xxx - 合同控件签署页面 (URL中需通过flowId指定)
https://open.yunyinsign.com/h5/pages/sealCorp/index - 企业印章列表页
https://open.yunyinsign.com/h5/pages/sealCorp/corporate - 企业印章新增页面
2. 通用跳转参数 (所有H5页面公共参数)
所有H5内嵌页面都需要通过URL query string传递以下公共参数:
参数名 是否必传 参数说明
appId 是 应用ID
accessToken 是 登录标识
userId 是 用户需要绑定的用户ID
3. 特定页面跳转参数
3.1 模板发起合同 (.../home/InitiateContract/components/detail)
除了公共参数外,还需要:
3.2 合同查看/签署/填写系列页面 (lookOver, signingPage, fillout, directInitiation)
除了公共参数外,还需要:
4. 与H5内嵌页面通信 (postMessage)
H5内嵌页面(通常在App的webview中或浏览器iframe中)与父容器的通信机制如下。推荐使用 window.addEventListener('message', ...) 监听。
父页面监听 (示例):
// 在内嵌H5的父页面 (例如原生App的JSBridge或另一个H5页面)
window.addEventListener('message', (event) => {
if (event.origin !== 'https://open.yunyinsign.com') { // 校验来源, open.yunyinsign.com 替换为实际域名
// return; // 正式环境建议开启来源校验
}
console.log('收到来自iframe的消息:', event.data); // event.data 通常是一个对象
if (event.data && typeof event.data === 'object' && event.data.type) {
switch (event.data.type) {
case 'goBack':
// 处理返回上一页的逻辑
console.log('事件: 返回上一页');
break;
case 'contract':
// 处理返回合同列表页的逻辑
console.log('事件: 返回合同列表页');
break;
case 'goShare':
// 处理返回分享页面的逻辑
console.log('事件: 返回分享页面');
break;
case 'message':
// 处理错误提示,例如Token过期
console.log('事件: 消息提示 - ', event.data.message || '无具体消息');
if(event.data.message && event.data.message.includes("Token过期")){
// 进行token刷新或重新登录操作
}
break;
default:
console.log('未知事件类型:', event.data.type);
}
}
});
// uniapp web-view 参考 (具体实现需查阅uniapp文档)
//
// methods: {
// handleWebViewMessage(event) {
// console.log('web-view组件message事件:', event.detail.data);
// // uniapp中 event.detail.data 通常是一个数组,包含发送的消息对象
// if (Array.isArray(event.detail.data) && event.detail.data.length > 0) {
// const messageData = event.detail.data[0];
// if(messageData && messageData.type) {
// /* ...处理逻辑同上... */
// console.log('Uniapp处理的类型:', messageData.type);
// }
// }
// }
// }