# 页面插件接入
需要解决的问题
- 登录态同步:其他应用登录后可直接使用企微中台页面
- 权限点同步:权限点应该由其他应用配置,把对应的权限点给到企微中台,企微中台做权限控制
- 页面之前通信:父页面(接入方)和 iframe(企微中台)通过 postmessage 通信,场景(父页面需要获取子页面高度)
# 域名
# PC 端
https://ewmp-bg.myscrm.cn(生产)
https://beta-ewmp-bg.myscrm.cn(预发布)
# 移动端
https://ewmp.myscrm.cn(生产)
https://beta-ewmp.myscrm.cn(预发布)
# 方案
用户登录接入方应用后使用企微中台插件的行为,可以看成是企微中台授权接入方应用使用企微中台的功能,因此可以借鉴 OAUTH 授权流程,只不过整个过程是静默进行的,整个过程实现相对简单。
# 登录过程
# 登出过程
# 父子页面通信
页面高度
当 iframe 内的子页面高度发生变化,子页面会通过 postmessage 通知父页面增加高度。从而避免滚动条嵌套。
// 加入到接入方父页面的前端代码
const message = JSON.stringify({ type: 'contentHeightChange', data: { height: 300 } }) // 高度变化
window.top?.postMessage(message, '*')
window.addEventListener(
'message',
(e) => {
if (typeof e.data === 'string') {
const pageContentInfo = JSON.parse(e.data)
if (iframe && pageContentInfo.type === 'contentHeightChange') {
// 全屏模式下,不改变iframe 的大小,防止页面排版错乱
if (pageContentInfo.data.width !== window.screen.width) {
iframe.height = pageContentInfo.data.height
}
}
}
},
false
)
iframe 登录状态过期
当 iframe 内的子页面登录状态过期时,子页面会通过 postmessage 通知父页面重走登录过程。
// 加入到接入方父页面的前端代码
const message = JSON.stringify({ type: 'loginExpiration', data: {} }) // 登录过期
window.top?.postMessage(message, '*')
window.addEventListener(
'message',
(e) => {
if (typeof e.data === 'string') {
const pageContentInfo = JSON.parse(e.data)
if (pageContentInfo.type === 'loginExpiration') {
// TODO: 重新获取 ticket,设置 iframe url 登录
// window.location.href = `${config.oldHost}${config.loginUrl}`
}
}
},
false
)
iframe 组件示例
<iframe
width="100%"
height="700"
ref={ifr}
onLoad={iframeLoad}
seamless
src={iframeUrl}
frameBorder="0"
scrolling="no"
name="ifr"
id="ifr"
allowFullScreen
sandbox="allow-same-origin allow-top-navigation allow-forms allow-scripts allow-popups allow-downloads"
/>
# 页面路由 path
# PC 端
示例:http://ewmp-bg.myscrm.cn/greeting?ticket={ticket}&orgcode={orgcode}
模块 | 页面名称 | 页面路由 | 页面描述 |
---|---|---|---|
欢迎语 | 欢迎语 | /greeting | 欢迎语列表页面 |
渠道码 | 渠道码管理 | /channelcode-management | 渠道码管理页面 |
素材库 | 素材管理 话术推荐 素材统计 | /material-center /words_recommendation /material-statistics | 素材库列表页面 话术推荐页面 素材统计首页 |
企微客服 | 客服帐号管理 自动回复管理 接待渠道管理 客服统计数据 自助导航 | /customer-service /auto-reply-management /receive-channels /customer-service/quality /reply-menu-management | 客服账号管理页面 自动回复管理首页 接待渠道管理首页 客服统计数据首页 自助导航首页 |
群发工具 | 群发客户 群发客户群 群发朋友圈 历史朋友圈 | /enterprise-mass /group-chat-list /wechat-moments /wechat-moments-history | 群发客户管理页面 群发客户群管理页面 群发朋友圈管理页面 历史朋友圈管理页 |
客户管理 | 离职继承(客户) 离职继承(员工) 在职继承 | /leave-inherit-customer /leave-inherit-employee /on-job-inherit | 离职继承(客户)首页 离职继承(员工)首页 在职继承首页 |
聊天管控 | 聊天记录 员工聊天管控 客户聊天管控首页 聊天超时提醒 | /chat-record /employee-chat-control /customer-chat-control /chat-timeout | 聊天记录首页 员工聊天管控首页 客户聊天管控首页 聊天超时提醒首页 |
公费电话 | 公费电话 | /public-phone | 公费电话 |
客户群 | 客户群 | /customer-group-chat | 客户群列表页面 |
企微任务 | 企微任务 | /mission-center | 企微任务首页 |
成员服务 | 客户流失提醒 | /customer-churn-statistics | 客户流失提醒首页 |
# 移动端
示例:https://ewmp.myscrm.cn/channel-code?ticket={ticket}
模块 | 页面名称 | 页面路由 | 页面描述 |
---|---|---|---|
渠道码 | 我的码 | /channel-code | 获取渠道码页面 |
素材库 | 素材中心 | /material-center | 素材中心首页 可选参数:share_type(分享类型)可选值:群发分享:1 、直接分享:2 (默认值) 例如:xxx?ticket={ticket}&share_type=1 |
话术推荐 | 话术推荐 | /words-recommend | 话术推荐首页 必要参数:ticket 例如:xxx?ticket={ticket} |
企微任务 | 任务详情(普通成员) | /mission-detail | 企微详情页普通成员页 必要参数:ticket、task_id (任务 id)、template_tag(普通成员标识:member_task_detail) 例如:xxx?ticket={ticket}&task_id={taskId}&template_tag=member_task_detail |
企微任务 | 企微任务(管理者任务首页) | /mission-center | 管理者查看的企微任务列表页面 必要参数ticket 例如:xxx?ticket={ticket} |
企微任务 | 进度统计(管理者统计页) | /progress-statistics | 管理者查看的统计页面 必要参数:ticket、task_id (任务 id) 例如:xxx?task_id=taskId&ticket={ticket} |
企微任务 | 任务详情(管理者我的任务页) | /mission-detail | 管理者自己的任务页 必要参数:ticket、task_id (任务 id)、 template_tag(管理者标识:manager_task_detail) 例如:?ticket={ticket}&task_id={taskId}&template_tag=manager_task_detail |
企微任务 | 我的勋章 | /my-medal | 成员完成任务后会颁发勋章,此页面展示成员的勋章信息 |
# 接入 API
应用方跳转到中台页面前,应用方后端需要请求中台的接口获取 ticket,然后通过 iframe 加载中台应用,把 ticket 参数拼接在 url 参数里面,由中台完成登录。
示例:http://ewmp-bg.myscrm.cn/{path}?ticket={ticket}
# 获取 ticket(PC 端)
请求方式: POST(HTTPS)
请求地址: https://nbd-api.myscrm.cn/open-bff-nbd-qw-bg/user/get_ticket
请求参数说明:
参数 | 必须 | 说明 |
---|---|---|
app_id | 是 | 企微中台应用 ID |
user_id | 是 | 接入方用户 id。 |
user_name | 是 | 接入方成员名。 |
permissions.funcCode | 否 | 企微中台能力编码。不传则没有权限 |
permissions.privileges | 否 | 接入方用户所拥有的权限代码集合 |
permissions.dataAccess | 否 | 接入方用户所拥有的数据权限集合 |
权限点说明:登录的时候要求传用户所有的权限。permissions 为数组,数组每一项是表示授予此用户此次会话对一个企微中台能力的权限。privileges 是所在功能的具体权限功能的集合,是一个数组,具体的值由企微中台定义。在每项企微中台能力介绍章节都会声明。
请求示例:
{
"app_id": "39fdda6e-a341-5e67-e243-d4ec9da063b8",
"user_id" : "7ea49153-ccbd-89d3-56a7-2137055498cb",
"user_name": "用户名",
"permissions": [ // 功能点权限, 不传则没有权限
{
"funcCode": "channnel_code", // 渠道码功能名称
"privileges": ["00", "01", "02"], // 功能列表,表示该用户由渠道码查看、新增、编辑权限
"dataAccess": {
"hideGlobalproject": true // 关联项目是否隐藏“全局”
}
}
]
}
返回示例:
{
"errcode" : 0,
"errmsg" : "ok",
"data": {
"ticket": "4b9ac71a-9d08-4c40-8269-011c6b581580",
"client_id": "a113ddbd-a22d-402b-95f0-427bd661c841",
"expires_in": 300
}
}
返回参数说明:
参数 | 说明 |
---|---|
errcode | 返回码。0 表示成功 |
errmsg | 对返回码的文本描述内容 |
data.ticket | 票据。用于前端嵌入页面的单点登录 |
data.client_id | 返回给接入方的客户端标识,有效期和会话同步,用于退出登录使用 |
data.expires_in | 有效期,只针对 ticket,单位秒 |
# 获取 ticket(移动端)
请求方式: POST(HTTPS)
请求地址: https://nbd-api.myscrm.cn/open-bff-nbd-qw/user/get_ticket 注意,移动端获取 ticket,参数 user_id 必须是企微成员用户 id,user_name 必须是企微成员用户名,pc 端获取 ticket 则没有要求
移动端全局项目权限配置,默认为有全局项目,如果不需要全局项目需要把 organ_code 给到企微中台开发人员进行配置
请求参数说明:
参数 | 必须 | 说明 |
---|---|---|
app_id | 是 | 企微中台应用 ID |
user_id | 是 | 企微成员用户 id |
user_name | 是 | 企微成员用户名 |
请求示例:
{
"app_id": "39fdf97b-2bc3-010d-82cd-e12d78b15714",
"user_id" : "wang_1",
"user_name": "用户名",
}
返回示例:
{
"errcode" : 0,
"errmsg" : "ok",
"data": {
"ticket": "4b9ac71a-9d08-4c40-8269-011c6b581580",
"client_id": "a113ddbd-a22d-402b-95f0-427bd661c841",
"expires_in": 300
}
}
# 退出登录
为了安全,当业务方主动退出后需要通知中台退出登录
请求方式:POST(HTTPS)
请求地址: https://nbd-api.myscrm.cn/open-bff-nbd-qw-bg/user/logout (PC 端)
请求参数说明:
参数 | 必须 | 说明 |
---|---|---|
app_id | 是 | 企微中台应用 ID |
user_id | 是 | 接入方用户。值是成员 id |
client_id | 是 | 客户端标识,获取 ticket 时获取 |
请求示例:
{
"appid": "39fdda6e-a341-5e67-e243-d4ec9da063b8",
"user_id" : "7ea49153-ccbd-89d3-56a7-2137055498cb",
"client_id": "a113ddbd-a22d-402b-95f0-427bd661c841"
}
返回示例
{
"errcode" : 0,
"errmsg" : "ok",
}
返回参数说明
参数 | 说明 |
---|---|
errcode | 返回码。0 表示成功 |
errmsg | 对返回码的文本描述内容 |
# 移动端注意事项
# js-sdk 调用
由于页面使用到了微信的 js-sdk,需要配置中台域名到企微后台,示例如下(下图展示的是生产环境域名):
# 素材中心分享说明
素材中心支持 2 中类型的分享形式:
- 直接分享给客户。需要通过聊天工具栏打开页面,因为从聊天窗口打开页面能获取到外部联系人。
- 需要选择客户(群发、朋友圈)。无法在页面获取到外部联系人的场景使用该方式(如从应用里面跳转),此时需要在 url 后面添加参数from=ykd。示例:https://ewmp.myscrm.cn/material-center?ticket={ticket}&from=ykd。
# 页面加载优化
# 背景
由于中台 H5 需要接入方传企微的用户信息,接入方需要自己完成企微的 oauth 认证获取用户信息,调用中台 api 获取 ticket,然后带上 ticket 参数跳转中台页面。整个流程较长影响页面加载速度。
# 优化方案
中台第一次登录后,会把登录态保存在 cookie 中,后续使用缓存登录,如果登录态失效则跳转接入方(接入方 url 通过参数 auth_url 告知中台),接入方重新获取 ticket 后跳转中台,中台使用 ticket 登录成功后把 sessionid 写入 cookie 中。时序图如下:其中云客多和用户中心是接入方。
# 示例如下
假设接入方链接为:https://access.com,下面用变量access代替
优化前链接:https://ewmp.myscrm.cn/channel-code?ticket={ticket}
优化后链接:https://ewmp.myscrm.cn/channel-code?auth_url=encodeURIComponent(access)&app_id={app_id}
# 说明
- 优化后链接中加入了app_id参数,这个是接入方应用在企微中台的 id,用来判断是否切换应用,是必须的
- 接入方的链接 access 需要实现获取 ticket 并跳转到中台页面
- 优化前 url 其他参数也需要在优化后链接中配置。如:https://ewmp.myscrm.cn/channel-code?auth_url=encodeURIComponent(access)&app_id={app_id}&from=ykd&other=xxx
# 移动端渠道码页面接入
移动端渠道码页面接入方式比较特殊,需要请求获取员工的渠道码页面接口获取地址
# 其他拓展
# 界面『项目』字样变量化
接入方在 iframe 链接后加上 prolabel 字段如下例:
https://ewmp-bg.myscrm.cn/greeting?ticket=5ab94798-dcd4-4707-a07b-1fbd58cf148d&orgcode=gzminjieadmin_test&prolabel=部门
界面(含子页面)会呈现如下展示(prolabel 字段不传或者传空,将默认展示'项目'二字)
# 样式,主题色配置
样式由 ui 设计,企微中台提供 2 种主题色配置的方法, 优先权: 链接参数配置 > organ_code 匹配 > 默认值
可以在链接中添加主题色参数 primary_color
例如: https://ewmp-bg.myscrm.cn?ticket={ticket}&primary_color={color}
color: 支持常见的 css 色值,需要对色值进行 encodeURIComponent 编码
注意:十六进制的颜色值如 #abcdef, 如果没有进行 encodeURIComponent 会导致链接中的参数丢失
联系企微中台开发,提供主题色,企微中台会根据接入方的 organ_code 来进行匹配
默认值: #f65c2c, 如果没有提供主题色,主题色使用默认值进行展示