@cqsjjb/website-platform-sdk
v1.0.5
Published
Website platform iframe SDK (open auth, SM2 config)
Downloads
616
Readme
@cqsjjb/website-platform-sdk
在业务页面中嵌入建站站点(建站系统页面)的浏览器端 SDK:通过开放账号接口完成用户鉴权(含 SM2 加密 config),并在页面容器内挂载 iframe,加载建站预览页;新用户会先出现授权确认,再继续创建账号。
特性
- ESM:适用于 Vite、Webpack 5、Create React App(配合配置)等现代打包工具,或原生
<script type="module">。 - TypeScript:提供类型声明,便于在 TS 项目中获得提示。
- 开放账号流程:
getUserInfo→(无用户数据则)授权弹窗 →createUser→ 拼接 iframe 地址并挂载。 - 事件回调:鉴权各阶段、授权确认/取消、挂载/卸载均可订阅。
- 依赖:
sm-crypto会随本包安装,用于对config做 SM2 加密,无需再单独引入 CDN 版本。
环境要求
- 浏览器(需
fetch、document、iframe 等 DOM API)。 - 建议使用 HTTPS 或与接口同策略的部署环境;跨域与 Cookie 策略由后端与浏览器共同决定。
安装
npm install @cqsjjb/website-platform-sdk安装后请确保工程能解析 ESM(主流前端脚手架默认支持)。不要用 file:// 直接打开本地 HTML,否则 ES 模块可能被浏览器拦截;本地预览请使用 dev server(如 npm run dev)或 npx serve 等。
使用示例
以下示例中,platformOrigin、appkey、config、host 请替换为与后端约定的实际值(platformOrigin 为建站站点根地址,开放账号接口与嵌入页同源)。
React(函数组件 + Hooks)
import { useEffect, useRef } from 'react';
import { createWebSite } from '@cqsjjb/website-platform-sdk';
import type { Website } from '@cqsjjb/website-platform-sdk';
export function WebsitePlatformEmbed() {
const containerRef = useRef<HTMLDivElement>(null);
const websiteRef = useRef<Website | null>(null);
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const website = createWebSite({
platformOrigin: 'https://你的建站站点根地址',
appkey: '你的 appkey',
sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
config: {
username: 'user001',
tenantId: '租户 ID',
clientId: '客户端 ID',
siteId: '站点 ID',
// 其余字段与后端约定一致
},
host: typeof window !== 'undefined' ? window.location.origin : '',
});
website.on('mount', () => {
console.log('iframe 已挂载');
});
website.on('getUserInfo:error', (_w, detail) => {
console.error('获取用户信息失败', detail?.err);
});
website.mount(el, {
width: '100%',
height: '600px',
style: { border: 'none' },
});
websiteRef.current = website;
return () => {
website.unmount();
websiteRef.current = null;
};
}, []);
return <div ref={containerRef} style={{ width: '100%', minHeight: 400 }} />;
}要点:
- 用
ref拿到挂载容器,在useEffect里调用mount,避免重复创建实例时可把createWebSite放进 effect 或配合useMemo/useRef存实例。 - 在 effect 清理函数里调用
website.unmount(),防止路由切换或组件卸载后残留 iframe 与监听。
Vue 3(<script setup>)
<template>
<div ref="containerRef" class="embed-wrap"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { createWebSite } from '@cqsjjb/website-platform-sdk';
import type { Website } from '@cqsjjb/website-platform-sdk';
const containerRef = ref<HTMLDivElement | null>(null);
let website: Website | null = null;
onMounted(() => {
const el = containerRef.value;
if (!el) return;
website = createWebSite({
platformOrigin: 'https://你的建站站点根地址',
appkey: '你的 appkey',
sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
config: {
username: 'user001',
tenantId: '租户 ID',
clientId: '客户端 ID',
siteId: '站点 ID',
},
host: typeof window !== 'undefined' ? window.location.origin : '',
});
website.on('mount', () => {
console.log('iframe 已挂载');
});
website.on('getUserInfo:error', (_w, detail) => {
console.error('获取用户信息失败', detail?.err);
});
website.mount(el, {
width: '100%',
height: '600px',
style: { border: 'none' },
});
});
onBeforeUnmount(() => {
website?.unmount();
website = null;
});
</script>
<style scoped>
.embed-wrap {
width: 100%;
min-height: 400px;
}
</style>要点:
- 在
onMounted中执行mount,此时模板已渲染,ref已指向 DOM。 - 在
onBeforeUnmount中调用unmount(),与页面或组件生命周期对齐。
传统 HTML(原生 ES Module)
页面需通过 HTTP/HTTPS 访问(本地可用任意静态服务)。在页面中增加容器,并用 type="module" 的脚本从 node_modules 引入(路径按实际安装位置调整,打包到静态资源后也可用相对路径)。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>建站站点嵌入示例</title>
</head>
<body>
<div id="embed-root" style="width:100%;height:600px;border:1px solid #ccc;"></div>
<script type="module">
import { createWebSite } from './node_modules/@cqsjjb/website-platform-sdk/dist/index.js';
const container = document.getElementById('embed-root');
if (!container) throw new Error('找不到容器');
const website = createWebSite({
platformOrigin: 'https://你的建站站点根地址',
appkey: '你的 appkey',
sm2PublicKeyDerHex: '基座提供的 SM2 公钥 DER(十六进制)',
config: {
username: 'user001',
tenantId: '租户 ID',
clientId: '客户端 ID',
siteId: '站点 ID',
},
host: window.location.origin,
});
website.on('mount', () => console.log('iframe 已挂载'));
website.on('getUserInfo:error', (_w, d) => console.error(d?.err));
website.mount(container, {
width: '100%',
height: '100%',
style: { border: 'none' },
});
// 若需要在离开页面前卸载,可绑定 beforeunload 或你自己的导航逻辑:
// window.addEventListener('beforeunload', () => website.unmount());
</script>
</body>
</html>若使用 Vite / Webpack 等多文件打包,通常不写死 node_modules 路径,而是在入口 JS 里写 import { createWebSite } from '@cqsjjb/website-platform-sdk',由打包器解析,再引入打包后的单文件脚本。
API 说明
createWebSite(options: WebsiteOptions): Website
创建 Website 实例。
| 字段 | 类型 | 说明 |
|------|------|------|
| platformOrigin | string | 必填。建站站点根地址(与开放账号接口、iframe 嵌入页同源),如 https://platform.example.com。末尾 / 可写可不写,SDK 会规范化。 |
| appkey | string | 必填。开放应用 appkey。 |
| sm2PublicKeyDerHex | string | 必填。SM2 公钥的 X.509 DER 十六进制串(与后端解密用私钥对应),用于加密 config。 |
| config | Record<string, unknown> | 可选。业务配置,将 JSON 序列化后经 SM2 加密 传给开放接口(字段名与后端约定一致)。嵌入建站预览页时还需 siteId、tenantId 等,与 buildPlatformIframeSrc 规则一致。 |
| host | string | 可选。请求体中的 host,一般填当前业务站点或后端认可的来源地址。 |
website.mount(container, options?)
将 SDK 挂到 一个 DOM 容器上,内部会异步请求开放接口并在成功后插入 iframe。
参数
container:HTMLElement | null。一般为div等块级容器;为null时会在控制台报错并中止。options:MountOptions,可选:
| 字段 | 类型 | 说明 |
|------|------|------|
| style | Record<string, string> | 应用到 iframe 的 CSS 行内样式(如 border: 'none')。 |
| width | string | iframe 宽度,如 '100%'、'800px'。 |
| height | string | iframe 高度。 |
| attrs | Record<string, string> | 额外 HTML 属性(如 id、title)。 |
流程概要
- 展示「正在获取用户信息…」Loading。
- 调用
getUserInfo;失败则触发getUserInfo:error并结束。 - 若返回中 没有用户数据(
!res.data):关闭 Loading → 展示 授权确认(确认 / 取消)。- 确认:触发
auth:confirm,再 Loading「正在创建用户…」,调用createUser。 - 取消:在容器内展示「您已取消授权」文案,触发
auth:cancel,不再创建用户、不挂 iframe。
- 确认:触发
- 若有用户数据或
createUser成功拿到data:根据data与config拼接建站预览页 URL(见buildPlatformIframeSrc),插入iframe,mounted = true,触发mount。
website.unmount()
卸载 iframe 并清空与本次挂载相关的内部状态;触发 unmount 事件。若当前未成功挂载 iframe,会在控制台提示错误。
实例属性(赋值即更新 iframe)
在 iframe 已存在 时,以下 setter 会同步到 DOM。
| 属性 | 说明 |
|------|------|
| website.width | 字符串,如 '100%'。 |
| website.height | 字符串。 |
| website.style | 行内样式对象。 |
| website.attrs | HTML 属性对象。 |
buildPlatformIframeSrc(data, platformOrigin, config?): string
根据开放接口返回的 用户态 与创建实例时的 config 生成建站预览页 URL(与 SDK 内部挂载 iframe 时一致)。第二参数可与 createWebSite 时一致,或传 website.platformOrigin;第三参数与 createWebSite({ config }) 一致,可省略(默认 {}),但预览路径需要 config.siteId、config.tenantId 等字段。
- 路径:
{platformOrigin}/official-website-design/container/Preview/{clientId}/{tenantId}/{siteId} clientId:data.clientId与config.clientId取其一或合并(与实现一致)。- 查询参数:附带
token(来自data.token)。
适用于需要自行打开新窗口或预校验 URL 的场景。
normalizePlatformOrigin(origin): string
去掉首尾空白与末尾 /,与 SDK 内部拼接开放接口、iframe 地址时的规范化规则一致;若你在配置中心存的是带尾斜杠的 URL,可先经此函数再传入 platformOrigin(也可直接传入,构造函数内会再次规范化)。
事件
使用 website.on(eventName, callback) 订阅。回调签名为 (website, detail?)(第一个参数为当前 Website 实例)。
| 事件名 | 触发时机 | detail 大致内容 |
|--------|----------|-------------------|
| getUserInfo:start | 即将请求 getUserInfo | { authOpts } |
| getUserInfo:success | getUserInfo HTTP 成功且已解析 JSON | { res, authOpts } |
| getUserInfo:error | getUserInfo 抛错或 HTTP 非 2xx | { err, authOpts } |
| auth:confirm | 用户点击「确认授权」后、请求 createUser 前 | { authOpts } |
| auth:cancel | 用户点击「取消」 | { authOpts } |
| createUser:start | 即将请求 createUser | { authOpts } |
| createUser:success | createUser 成功 | { res1, authOpts } |
| createUser:error | createUser 失败 | { err, authOpts } |
| mount | iframe 已插入容器并完成绑定 | 无额外载荷(回调第一个参数仍为 Website 实例) |
| heartbeat:start | iframe 挂载后心跳定时器启动(仅当 token 存在时) | 无额外载荷 |
| token:expired | 心跳检测到 token 失效 | 无额外载荷(会同步隐藏 iframe 并弹出「重新授权」对话框) |
| unmount | 调用 unmount() 并完成清理 | 无额外载荷 |
使用 website.off(eventName) 可移除对应监听。
TypeScript
包导出类型包括:WebsiteOptions、MountOptions、AuthOpts、WebsiteUserData、OpenAccountEnvelope 等。
import {
createWebSite,
buildPlatformIframeSrc,
normalizePlatformOrigin,
type WebsiteOptions,
} from '@cqsjjb/website-platform-sdk';
const origin = normalizePlatformOrigin('https://platform.example.com/');
const url = buildPlatformIframeSrc(userData, origin, {
tenantId: '租户 ID',
siteId: '站点 ID',
clientId: '客户端 ID',
});与后端约定
platformOrigin决定开放账号接口与 iframe 的基址,须与当前环境建站站点部署地址一致(测试 / 生产分别配置)。config字段须与后端解密、验签规则一致(SM2 加密由本包在浏览器侧完成)。- 若贵司接口在 HTTP 层之外还有业务错误码约定,请在业务代码中根据返回体自行处理(例如统一提示)。
常见问题
1. 页面里 import 报错 / 模块找不到
请通过 开发服务器或静态站点 访问页面,不要使用 file:// 打开含 ES Module 的 HTML。
2. 安装后没有类型提示
确认已正确安装依赖,且 IDE 使用的是包内的类型入口(由 package.json 的 "types" 字段指定)。
3. 新用户一直停在 Loading
检查网络、开放接口是否可达,以及 platformOrigin / appkey / config / host 是否与当前环境一致。
4. 授权成功但无法显示 这可能是跨域问题导致,需要联系技术人员处理。
开源协议
ISC(见发布包内 package.json 的 license 字段)。
