iframe-comlink-sdk
v1.0.18
Published
A TypeScript SDK for iframe communication using Comlink
Maintainers
Readme
Simple Iframe SDK
简单易用的 iframe 通信 SDK,提供六个核心 API,支持连接失败自动重试。
安装
npm install iframe-comlink-sdk使用方法
父页面
import { AIAssistantSDK } from 'iframe-comlink-sdk'
const sdk = new AIAssistantSDK({
onSubmit: (data) => {
console.log('收到子页面数据:', data)
},
onSelect: (data) => {
console.log('收到子页面选择数据:', data)
// data 结构:{ customString?, businessType?, data: [{ label, value, originData? }] }
console.log('自定义回复内容:', data.customString)
console.log('业务类型:', data.businessType)
console.log('选择的项:', data.data)
},
getToken: () => {
return {
/** 商龙云token */
sly_token: 'xxx',
/** 组织ID */
orgId: 'yyy',
/** 组织类型: 0-门店, 1-集团 */
orgType: 0,
/** 账户ID */
accountId: 'zzz'
}
},
onOpenLink: (data) => {
console.log('收到子页面打开链接请求:', data)
// 处理打开链接逻辑,比如在新标签页中打开
if (data.url) {
window.open(data.url, '_blank')
}
}
})OpenLinkData数据结构
SDK使用的OpenLinkData数据结构如下:
interface OpenLinkData {
/** 必传,固定值 */
code: 'menuJump'
/** 必传 业务线跳自己菜单或者表单上时,对应着他们自己的菜单 code,sourceModule 他们肯定知道,业务线跳商龙云菜单时,需要商龙云同学告诉业务线同学对应的 menuId */
id: string
/** 非必传 业务线自己的菜单 id,打开业务线自己表单时,需要传 */
sourceId?: string
/** 必传 add:新建,edit:详情, menu:正常菜单跳转 */
type: 'add' | 'edit' | 'menu'
/** 非必传 跳转详情或者新建的时候(业务线/商龙云),需要传此值, ---新建时为 add,详情时为 detailId */
detailId?: string
/** 非必传 跳转新建或者详情时(业务线/商龙云),需要传 */
name?: string
/** 必传 商龙云:000, 供应链:010 新餐饮:012 老餐饮: 005 */
sourceCode: '000' | '010' | '012' | '005'
/** 非必传 新建或者详情时(业务线/商龙云),需要传 */
url?: string
/** 非必传 跳转商龙云详情或者新建的时候,需要时传此值 */
query?: Record<string, any>
/** 在业务线的新建或者编辑标签页时,点击保存或者保存并新建成功后,进行通讯时需要传此值,true:需要替换当前标签页(新建->编辑、 编辑->新建) */
replaceTab?: boolean
/** 业务线的新建或者编辑页签,离开或者关闭时,是否需要通知业务线进行更改校验,需要为 true */
formCheck?: boolean
/** 是否为报表类型的菜单 */
isReport?: boolean
}SelectionData数据结构
SDK使用的SelectionData数据结构如下(用于 onSelect 方法):
interface SelectionItem {
/** 显示标签 */
label: string
/** 选择值(通常是id) */
value: string | number
/** 原始数据(业务方的完整数据) */
originData?: any
}
interface SelectionData {
/** 自定义字符串(用于自定义显示回复内容) */
customString?: string
/** 业务类型标识 */
businessType?: string
/** 选择的数据(支持单选和多选) */
data: SelectionItem[]
}onSelect 使用示例
单选场景
// 选择单个商品
await sdk.onSelect({
customString: '已选择商品:iPhone 15 Pro',
businessType: 'product',
data: [
{
label: 'iPhone 15 Pro',
value: 'P001',
originData: {
id: 'P001',
name: 'iPhone 15 Pro',
price: 8999,
stock: 100
}
}
]
})
// 选择单个客户
await sdk.onSelect({
customString: '已选择客户:张三',
businessType: 'customer',
data: [
{
label: '张三',
value: 'C001',
originData: {
id: 'C001',
name: '张三',
phone: '13800138000',
address: '北京市朝阳区'
}
}
]
})多选场景
// 选择多个商品
await sdk.onSelect({
customString: '已选择3个商品',
businessType: 'product',
data: [
{
label: 'iPhone 15 Pro',
value: 'P001',
originData: { id: 'P001', name: 'iPhone 15 Pro', price: 8999 }
},
{
label: 'MacBook Pro',
value: 'P002',
originData: { id: 'P002', name: 'MacBook Pro', price: 12999 }
},
{
label: 'AirPods Pro',
value: 'P003',
originData: { id: 'P003', name: 'AirPods Pro', price: 1999 }
}
]
})
// 选择多个供应商
await sdk.onSelect({
customString: '已选择2个供应商',
businessType: 'supplier',
data: [
{
label: '供应商A',
value: 'S001',
originData: { id: 'S001', name: '供应商A', contact: '李四' }
},
{
label: '供应商B',
value: 'S002',
originData: { id: 'S002', name: '供应商B', contact: '王五' }
}
]
})使用示例
// 打开新建页面
await sdk.onOpenLink({
code: 'menuJump',
id: 'productModule',
type: 'add',
detailId: 'add',
name: '新建商品',
sourceCode: '000',
url: 'https://example.com/product/new',
formCheck: true
})
// 打开编辑页面
await sdk.onOpenLink({
code: 'menuJump',
id: 'productModule',
type: 'edit',
detailId: '12345',
name: '编辑商品',
sourceCode: '000',
url: 'https://example.com/product/edit/12345',
query: { readonly: false },
replaceTab: true,
formCheck: true
})
// 普通菜单跳转
await sdk.onOpenLink({
code: 'menuJump',
id: 'reportModule',
type: 'menu',
name: '销售报表',
sourceCode: '000',
isReport: true
})子页面
import { AIAssistantSDK } from 'iframe-comlink-sdk'
const sdk = new AIAssistantSDK({
onSetToken: (tokenData) => {
console.log('收到父页面发送的token:', tokenData)
// 处理接收到的token数据
localStorage.setItem('currentTokens', JSON.stringify(tokenData))
}
})
// 🎯 智能等待:以下方法会自动等待SDK初始化完成,无需担心时序问题
// 发送数据给另一个子页面(双iframe模式)或父页面(单iframe模式)
await sdk.onSubmit({ message: 'hello' })
// 发送选择数据给另一个子页面(双iframe模式)或父页面(单iframe模式)
await sdk.onSelect({
customString: '已选择商品:iPhone 15 Pro',
businessType: 'product',
data: [{ label: 'iPhone 15 Pro', value: 'P001', originData: { id: 'P001', name: 'iPhone 15 Pro', price: 8999 } }]
})
// 请求父页面打开链接(自动等待初始化完成)
const result = await sdk.onOpenLink({
code: 'menuJump', // 必传,固定值
id: 'sourceModule', // 必传,菜单code或目标模块ID
sourceId: 'myMenuId', // 非必传,业务线自己的菜单ID
type: 'add', // 必传,操作类型:add-新建,edit-详情,menu-菜单跳转
detailId: 'add', // 非必传,新建时为'add',详情时为具体ID
name: '新建商品', // 非必传,标签页名称
sourceCode: '000', // 必传,系统代码:000-商龙云,010-供应链,012-新餐饮,005-老餐饮
url: 'https://example.com/form', // 非必传,跳转URL
query: { productId: 123 }, // 非必传,查询参数
replaceTab: false, // 非必传,是否替换当前标签页
formCheck: true, // 非必传,离开时是否需要表单校验
isReport: false // 非必传,是否为报表类型
})
console.log('新页面返回的数据:', result)
// 获取父页面的token数据(自动等待初始化完成)
const tokens = await sdk.getToken()
// 获取另一个子页面或父页面的表单数据(自动等待初始化完成)
// 需要URL包含openlink_id参数
const formData = await sdk.getFormData()
console.log('获取到的表单数据:', formData)
## API
### 连接管理
- `linkSingleFrame(iframe)` - 父页面连接单个iframe(支持onOpenLink功能)
- `linkFrame(iframe1, iframe2)` - 父页面连接两个 iframe(完整通信功能)
- `retryConnection()` - 父页面手动重试连接
- `getConnectionStatus()` - 获取当前连接状态
### 数据通信(自动等待初始化)
- `onSubmit(data)` - 子页面发送数据给另一个子页面或父页面
- `onSelect(data)` - 子页面发送选择数据(SelectionData对象)给另一个子页面或父页面
- `onOpenLink(data)` - 子页面请求父页面打开链接,传入OpenLinkData对象
- `getToken()` - 子页面向父页面请求token数据
- `getFormData()` - 子页面获取另一个子页面或父页面的表单数据(需要URL包含openlink_id参数)
- `setToken(iframe, tokenData)` - 父页面向指定子页面发送token数据
- `retryConnection()` - 父页面手动重试连接
- `getConnectionStatus()` - 获取当前连接状态
## 重试机制
SDK 内置了连接失败重试机制:
- 默认重试3次,每次间隔2秒
- 可通过构造函数参数自定义重试次数和间隔
- 支持手动调用 `retryConnection()` 重新尝试连接
- 所有Comlink连接操作都会自动重试
## AI助手环境检测
被AI助手嵌入或者打开的页面会有一个 `openlink_id` 的参数,可以用这个参数判断是否在AI助手中:
```javascript
// 检查是否在AI助手环境中
const urlParams = new URLSearchParams(window.location.search);
const isInAIAssistant = urlParams.has('openlink_id');
if (isInAIAssistant) {
console.log('当前页面运行在AI助手中');
const openlinkId = urlParams.get('openlink_id');
console.log('OpenLink ID:', openlinkId);
}重试机制
SDK 内置了连接失败重试机制:
- 默认重试3次,每次间隔2秒
- 可通过构造函数参数自定义重试次数和间隔
- 支持手动调用
retryConnection()重新尝试连接 - 所有Comlink连接操作都会自动重试
getFormData API
getFormData() 方法用于在子页面中获取另一个子页面或父页面的表单数据。
🎯 新特性:自动等待初始化
现在 getFormData() 支持自动等待SDK初始化完成,确保在子页面完全初始化之前调用也能正常工作。
特性
- URL 校验:只有当前页面URL包含
openlink_id参数时才能调用此方法 - 双向获取:可以获取另一个子页面的数据,或获取父页面的数据
- 自动降级:如果对等连接不可用,会自动尝试从父页面获取数据
使用方法
父页面配置
const sdk = new AIAssistantSDK({
getFormData: () => {
// 返回父页面的表单数据
return {
parentField1: 'value1',
parentField2: 'value2',
currentUser: localStorage.getItem('username')
}
}
})子页面配置
const sdk = new AIAssistantSDK({
getFormData: () => {
// 返回当前子页面的表单数据
return {
username: document.querySelector('#username').value,
email: document.querySelector('#email').value,
selectedOption: document.querySelector('#option').value
}
}
})
// 在需要的时候获取另一个页面的表单数据
// 注意:只有URL包含openlink_id参数时才能调用
try {
const formData = await sdk.getFormData()
console.log('获取到的表单数据:', formData)
// 使用获取到的数据预填表单
if (formData.username) {
document.querySelector('#username').value = formData.username
}
} catch (error) {
console.error('获取表单数据失败:', error)
}数据流向
- 双iframe模式:子页面A → 子页面B 的表单数据
- 单iframe模式:子页面 → 父页面 的表单数据
- 连接降级:如果对等连接断开,自动切换到父页面数据源
注意事项
- 必须在URL包含
openlink_id参数的页面中调用 - 需要配置对应的
getFormData回调函数 - 数据会自动序列化,移除Vue等框架的Proxy包装
- 如果目标页面未配置回调或连接断开,会抛出错误
SDK使用的Token数据结构如下:
interface TokenData {
/** 商龙云token */
sly_token: string;
/** 组织ID */
orgId: string;
/**
* orgType 可以是字符串或数字,表示组织类型
* 0 - 门店
* 1 - 集团
*/
orgType: string | number;
/** 账户ID */
accountId: string;
}示例
查看 examples/ 目录下的完整示例。
