smh-web-uikit
v1.1.2
Published
SMH Web UIKit — 基于 React 的云盘文件管理组件库
Maintainers
Readme
SMH Web UIKit 接入文档
简介
smh-web-uikit 是一个基于 React 的云盘文件管理 UIKit,提供完整的文件浏览、上传、下载、删除、重命名、移动、搜索、分享等功能。内置两种 UI 模式(compact 简洁 / full 完整),接入方只需提供必要的配置参数和一个 accessToken 获取函数,即可快速嵌入云盘能力。
安装
npm install smh-web-uikit宿主项目 peerDependencies 要求
| 依赖 | 版本要求 |
|------|---------|
| react | ^18.0.0 |
| react-dom | ^18.0.0 |
宿主项目需自行安装上述 peerDependencies。UIKit 内部不依赖任何第三方 UI 组件库,所有 UI 均为原生实现。
SDK 依赖说明
smh-web-uikit UIKit 的完整运行依赖腾讯云 SMH 官方提供的两个 SDK,分别用于前端和后端:
smh-js-sdk(前端 SDK)
| 项目 | 说明 |
|------|------|
| 使用方 | smh-web-uikit(UIKit 内部已集成) |
| 版本要求 | ^1.0.5 |
| 安装 | UIKit 内部已包含,接入方无需单独安装 |
| 用途 | 前端直连 SMH API,完成文件浏览、上传、下载、删除等操作 |
核心能力:
- 目录操作 —
client.directory.listDirectoryByPage()/createDirectory()/deleteDirectory():文件列表分页查询、创建/删除目录 - 文件操作 —
client.file.deleteFile()/infoFile():文件删除、获取文件详情 - 文件上传 —
client.createUploadTask():支持分片上传、断点续传、秒传检测,提供进度回调和状态变更通知 - 使用量统计 —
client.usage.getUsage():获取当前空间的配额和已用容量
UIKit 内部使用示例(接入方无需关心):
import { SMHClient, TaskStatus } from 'smh-js-sdk'
const client = new SMHClient({
basePath: 'https://api.tencentsmh.cn',
libraryId: 'smhxxx-xxxxx',
spaceId: 'spaceyyy',
accessToken: 'your_access_token',
})
// 获取文件列表
const res = await client.directory.listDirectoryByPage({
filePath: '',
byPage: 1,
page: 1,
pageSize: 100,
})
// 上传文件(支持分片、断点续传)
const uploader = client.createUploadTask({
filePath: 'docs/hello.txt',
file: fileObject,
conflictResolutionStrategy: 'overwrite',
onStateChange: (checkpoint, state, error) => {
if (state === TaskStatus.SUCCESS) console.log('上传成功')
},
onProgress: (info) => console.log(`进度: ${Math.floor(info.progress * 100)}%`),
})
uploader.start()smh-node-sdk(后端 SDK)
| 项目 | 说明 |
|------|------|
| 使用方 | 接入方的后端服务 |
| 版本要求 | ^1.0.0 |
| 安装 | npm install smh-node-sdk |
| 用途 | 后端调用 SMH 管理 API,签发 accessToken、管理空间和配额 |
核心能力:
- Token 签发 —
smh.token.createToken():签发admin/space_admin级别的 accessToken(需要library_secret,仅后端持有) - 空间管理 —
smh.space.listSpace()/createSpace()/deleteSpace():租户空间的增删查 - 配额管理 —
smh.quota.getQuota()/createQuota()/updateQuota():存储配额的查询与设置 - 使用量统计 —
smh.usage.getUsage():获取空间容量使用情况
后端使用示例:
const { SMHClient } = require('smh-node-sdk')
const smh = new SMHClient({ basePath: 'https://api.tencentsmh.cn' })
smh.setDefaultLibraryId('smhxxx-xxxxx')
// 签发 space_admin 级别的 token(供前端 UIKit 使用)
const tokenData = await smh.token.createToken({
libraryId: 'smhxxx-xxxxx',
librarySecret: 'your_secret', // ⚠️ 仅后端持有
spaceId: 'spaceyyy',
grant: 'space_admin',
period: 1800, // 30分钟
})
// 创建租户空间
const space = await smh.space.createSpace({
libraryId: 'smhxxx-xxxxx',
accessToken: adminToken,
userId: 'user123',
createSpaceRequest: {
allowPhoto: true,
isPublicRead: true,
allowVideo: true,
},
})
// 查询空间使用量
const usage = await smh.usage.getUsage({
libraryId: 'smhxxx-xxxxx',
spaceIds: 'spaceyyy',
accessToken: adminToken,
userId: 'user123',
})两个 SDK 的分工关系
┌──────────────────────────────────────────────────────────┐
│ 浏览器 (前端) │
│ │
│ smh-web-uikit 内部使用 smh-js-sdk 直连 SMH API │
│ ├── 文件浏览、上传、下载、删除、重命名、移动 │
│ └── 前端持有 accessToken(由后端签发,不含 secret) │
│ │
└──────────────────────────┬───────────────────────────────┘
│ 调用 getAccessToken()
│ 获取 accessToken
▼
┌──────────────────────────────────────────────────────────┐
│ Node.js 服务端 (后端) │
│ │
│ 接入方后端使用 smh-node-sdk 调用 SMH 管理 API │
│ ├── 签发 accessToken(需要 library_secret,仅后端持有) │
│ ├── 空间管理(创建/删除租户空间) │
│ ├── 配额管理(查询/修改存储上限) │
│ └── 使用量统计 │
│ │
└──────────────────────────────────────────────────────────┘⚠️ 安全原则:
library_secret仅存在于服务端,前端通过后端签发的accessToken访问 SMH API,永远不会接触到密钥。UIKit 内部的smh-js-sdk只需要accessToken即可工作。
快速开始
import { SpaceDrive } from 'smh-web-uikit'
import 'smh-web-uikit/dist/style.css'
function App() {
// accessToken 提供函数(详见下方说明)
const getAccessToken = async () => {
const res = await fetch('/api/your-backend/get-smh-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ spaceId: 'your-space-id' }),
})
const data = await res.json()
return {
accessToken: data.accessToken,
expiresAt: data.expiresAt, // 支持:毫秒时间戳、秒级时间戳、ISO 8601 字符串(含纳秒精度)
}
}
return (
<SpaceDrive
basePath="https://api.tencentsmh.cn"
libraryId="smhxxx-xxxxx"
spaceId="space-xxxxx"
getAccessToken={getAccessToken}
uiMode="full" // 'full'(完整模式)或 'compact'(简洁模式)
/>
)
}Props 参数说明
<SpaceDrive /> 组件
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| basePath | string | ✅ | - | SMH API 基础路径,如 https://api.tencentsmh.cn |
| libraryId | string | ✅ | - | SMH 媒体库 ID,由腾讯云 SMH 控制台创建后获取 |
| spaceId | string | ✅ | - | SMH 空间 ID,标识一个独立的存储空间 |
| getAccessToken | Function | ✅ | - | accessToken 提供函数,详见下方 |
| enableSearch | boolean | ❌ | false | 是否启用搜索功能(顶部工具栏搜索框) |
| enableRecycleBin | boolean | ❌ | false | 是否启用回收站功能(顶部工具栏回收站按钮 + 回收站面板) |
| uiMode | 'compact' \| 'full' | ❌ | 'full' | UI 模式切换,详见下方说明 |
| title | string | ❌ | '云盘' | 顶部标题文字,完整模式(full)下显示在左上角 |
uiMode — UI 模式切换
SpaceDrive 组件内置两种 UI 风格,通过 uiMode 参数切换:
| 模式 | 值 | 说明 |
|------|-----|------|
| 完整模式 | 'full'(默认) | 「流动蓝图」设计风格,功能齐全,适合独立云盘页面 |
| 简洁模式 | 'compact' | 传统列表设计,轻量紧凑,适合嵌入 Drawer/侧栏等有限空间 |
功能对比:
| 特性 | compact 简洁 | full 完整 |
|------|:-:|:-:|
| 文件列表(表格) | ✅ | ✅ |
| 网格视图切换 | — | ✅ |
| 网格拖拽框选 + Shift 多选 | — | ✅ |
| 底部浮动批量操作栏(下载/删除) | — | ✅ |
| 排序控件(时间/名称/大小) | — | ✅ |
| 分享功能(临时链接) | — | ✅ |
| 视频/音频预览 | — | ✅ |
| Markdown 渲染预览 | — | ✅ |
| 批量上传(数量/大小限制) | — | ✅ |
| 上传详情面板(队列/速度/耗时/进度) | — | ✅ |
| 回收站(恢复/永久删除/清空) | — | ✅(需 enableRecycleBin) |
| 可收起侧边栏 | ✅ | — |
| 行内重命名(点击即编辑) | ✅ | 弹窗式 |
| 配额进度条 | 侧边栏 | 顶部信息栏 |
| 搜索结果按文件夹分组 | ✅ | 平铺列表 |
| 上传速度/秒传状态展示 | ✅ | 上传详情面板 |
示例:
// 完整模式(默认)— 适合独立页面
<SpaceDrive
basePath="https://api.tencentsmh.cn"
libraryId="smhxxx-xxxxx"
spaceId="space-xxxxx"
getAccessToken={getAccessToken}
uiMode="full"
enableRecycleBin // 启用回收站功能(默认关闭)
/>
// 简洁模式 — 适合嵌入 Drawer、侧栏
<SpaceDrive
basePath="https://api.tencentsmh.cn"
libraryId="smhxxx-xxxxx"
spaceId="space-xxxxx"
getAccessToken={getAccessToken}
uiMode="compact"
/>💡 两种 UI 组件通过
import()懒加载,切换模式不会增加另一种模式的打包体积。
组件目录结构
两种 UI 模式的代码按目录隔离,互不依赖:
src/components/cloudFile/
├── compact/ # compact 简洁模式
│ ├── file.jsx # 主组件(含内联预览、侧边栏、缩略图等)
│ └── file.css # 样式
│
└── full/ # full 完整模式(流动蓝图)
├── FileSpace.jsx # 主组件(表格/网格视图、框选、批量操作等)
├── FileActions.jsx # 文件操作下拉菜单
├── DocPreviewOverlay.jsx # 文档预览全屏遮罩
├── ImagePreviewOverlay.jsx # 图片/视频/音频预览遮罩
├── RecycleBin.jsx # 回收站面板
├── UploadPanel.jsx # 上传详情面板(队列/速度/耗时)
├── helpers.jsx # 工具函数(文件图标、格式化、路径处理等)
└── FileSpace.css # 样式维护时只需关注对应模式的子目录,修改一种模式不会影响另一种。
核心概念
参数获取方式
1. basePath — SMH API 基础路径
SMH 服务的 API 域名地址,由腾讯云 SMH 服务提供。格式如:
https://api.tencentsmh.cn该值通常由后端配置提供,不同环境(测试/生产)可能不同。
2. libraryId — 媒体库 ID
在 腾讯云 SMH 控制台 创建媒体库后获得的唯一标识。格式如:
smhxxx-xxxxx一个
libraryId下可以包含多个spaceId(空间)。
3. spaceId — 空间 ID
每个用户/租户对应一个独立的存储空间,由后端通过 SMH API 创建。格式如:
spaceyyyyyy不同用户应使用不同的
spaceId,以实现数据隔离。
4. getAccessToken — Token 提供函数(重点)
这是接入方必须实现的核心函数。UIKit 内部会在以下时机调用此函数:
- 初始化时:组件挂载后首次获取 token
- token 即将过期时:UIKit 内部每 30 秒检查一次,当 token 距过期不足 5 分钟时自动调用续期
- 请求发现 token 失效时:API 请求返回 token 无效错误时自动重试
函数签名:
type GetAccessToken = () => Promise<{
accessToken: string // SMH 访问令牌
expiresAt: number | string // 过期时间,支持以下格式:
// - 毫秒级时间戳(如 1711468800000)
// - 秒级时间戳(如 1711468800,自动 ×1000)
// - ISO 8601 字符串(如 "2026-04-04T02:23:20.923Z")
// - 带纳秒精度的字符串(如 "2026-04-04T02:23:20.923548596Z",自动截断)
// - Date 对象
// SDK 内部会自动统一转为毫秒时间戳,无效值会使用默认有效期(2小时)兜底
}>实现示例:
const getAccessToken = async () => {
const res = await fetch('/api/your-backend/generate-space-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ spaceId: 'your-space-id' }),
})
if (!res.ok) {
throw new Error('获取访问令牌失败')
}
const data = await res.json()
return {
accessToken: data.accessToken, // SMH accessToken
expiresAt: data.expiresAt, // 毫秒级过期时间戳
}
}⚠️ 重要:
getAccessToken函数的引用应保持稳定(使用useCallback或定义在组件外部),避免因引用变化导致组件重复初始化。
后端需要提供的接口
接入方的后端需要实现一个 生成 SMH Space Token 的接口,供前端 getAccessToken 函数调用。
接口职责
- 验证当前用户的身份和权限
- 调用 SMH API 生成指定
spaceId的accessToken - 返回
accessToken和过期时间
SMH 生成 Token 的 API
GET {basePath}/api/v1/token?library_id={libraryId}&library_secret={librarySecret}&Grant=space_admin&Period=7200&spaceId={spaceId}| 参数 | 说明 |
|------|------------------------------|
| library_id | 媒体库 ID |
| library_secret | 媒体库密钥(仅后端持有,切勿暴露给前端) |
| Grant | 授权级别,推荐 space_admin |
| Period | token 有效期(秒),推荐 1800(30分钟) |
| spaceId | 目标空间 ID |
后端接口返回格式(建议)
{
"accessToken": "xxx-access-token-xxx",
"expiresAt": 1711468800000,
"libraryId": "smhxxx-xxxxx",
"spaceId": "spaceyyyyyy",
"basePath": "https://api.tencentsmh.cn"
}其中
expiresAt为毫秒级时间戳,计算方式:Date.now() + Period * 1000
Node.js 后端示例
app.post('/api/generate-space-token', async (req, res) => {
const { spaceId } = req.body
// 1. 验证用户权限(根据业务逻辑)
// ...
// 2. 调用 SMH API 获取 token
const params = new URLSearchParams({
library_id: process.env.SMH_LIBRARY_ID,
library_secret: process.env.SMH_LIBRARY_SECRET,
Grant: 'space_admin',
Period: '1800', // 30分钟
spaceId,
})
const response = await fetch(`${process.env.SMH_BASE_PATH}/api/v1/token?${params}`)
const tokenData = await response.json()
// 3. 计算过期时间并返回
const expiresAt = Date.now() + 30 * 60 * 1000
res.json({
accessToken: tokenData.accessToken,
expiresAt,
libraryId: process.env.SMH_LIBRARY_ID,
spaceId,
basePath: process.env.SMH_BASE_PATH,
})
})完整接入示例
以下是一个在管理后台中嵌入云盘的完整示例:
import { useState, useCallback, useRef } from 'react'
import { Drawer, Button } from 'tdesign-react' // 示例使用 TDesign,宿主项目可使用任意 UI 库
import { SpaceDrive, clearConfig as clearDriveConfig } from 'smh-web-uikit'
import 'smh-web-uikit/dist/style.css'
export default function MyPage() {
const [drawerVisible, setDrawerVisible] = useState(false)
const [driveConfig, setDriveConfig] = useState(null)
const spaceIdRef = useRef('')
const cachedTokenRef = useRef(null)
// accessToken 提供函数(引用稳定)
const getAccessToken = useCallback(async () => {
// 如果有缓存的 token(首次进入时预获取),直接返回
if (cachedTokenRef.current) {
const cached = cachedTokenRef.current
cachedTokenRef.current = null
return cached
}
const res = await fetch('/api/generate-space-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ spaceId: spaceIdRef.current }),
})
if (!res.ok) throw new Error('获取访问令牌失败')
const data = await res.json()
return {
accessToken: data.accessToken,
expiresAt: data.expiresAt,
}
}, [])
// 打开云盘
const handleOpenDrive = async (spaceId) => {
spaceIdRef.current = spaceId
// 预获取 token 和配置信息
const res = await fetch('/api/generate-space-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ spaceId }),
})
const data = await res.json()
// 缓存首次 token,避免 UIKit 初始化时重复请求
cachedTokenRef.current = {
accessToken: data.accessToken,
expiresAt: data.expiresAt,
}
setDriveConfig({
basePath: data.basePath,
libraryId: data.libraryId,
spaceId,
getAccessToken,
})
setDrawerVisible(true)
}
// 关闭云盘
const handleCloseDrive = () => {
setDrawerVisible(false)
setTimeout(() => {
setDriveConfig(null)
cachedTokenRef.current = null
clearDriveConfig() // 清理 UIKit 内部状态
}, 300)
}
return (
<div>
<Button onClick={() => handleOpenDrive('space-xxxxx')}>
打开云盘
</Button>
<Drawer
visible={drawerVisible}
onClose={handleCloseDrive}
size="85%"
destroyOnClose
>
{driveConfig && (
<SpaceDrive
basePath={driveConfig.basePath}
libraryId={driveConfig.libraryId}
spaceId={driveConfig.spaceId}
getAccessToken={driveConfig.getAccessToken}
enableSearch={true} // 启用搜索功能(默认关闭)
uiMode="compact" // 嵌入 Drawer 时推荐使用简洁模式
/>
)}
</Drawer>
</div>
)
}导出的工具函数(高级用法)
除了 <SpaceDrive /> 组件,UIKit 还导出了以下工具函数,供高级场景使用。所有 API 均从 smh-web-uikit 统一导入,只需一行 import 即可:
import {
// ---- 核心组件 ----
SpaceDrive, // 核心组件(自动根据 uiMode 切换 UI)
FilePage, // 简洁模式文件管理组件(底层组件,高级用法)
FileSpace, // 完整模式文件管理组件(流动蓝图,高级用法)
// ---- 配置与 Token 管理 ----
setSmhConfig, // 手动设置 SMH 配置
getAccessToken, // 获取当前 accessToken
getLibraryId, // 获取当前 libraryId
getSpaceId, // 获取当前 spaceId
getBasePath, // 获取当前 basePath
getTokenExpireInfo, // 获取 token 过期时间信息
isTokenExpiringSoon, // 检查 token 是否即将过期
isTokenExpired, // 检查 token 是否已过期
ensureValidToken, // 确保 token 有效(自动续期)
initToken, // 初始化 token
clearConfig, // 清除所有配置和 token(包括所有 space 的缓存)
clearSpaceCache, // 清除指定 space 的 token 缓存
// ---- 文件操作 API ----
getFileList, // 获取文件列表(分页)
uploadFile, // 上传文件(分片/断点续传/秒传)
delFile, // 删除文件
delDirectory, // 删除目录
createDirectory, // 创建文件夹
moveFile, // 移动文件
moveDirectory, // 移动目录
renameFile, // 重命名文件
renameDirectory, // 重命名目录
getFileInfo, // 获取文件详情
getPreview, // 获取预览地址或内容
getDocPreviewUrl, // 获取文档在线预览 URL
downloadFile, // 下载文件(触发浏览器下载)
getFilePreviewUrlOrContent,// 自动判断类型获取预览
getSpaceUsage, // 获取空间配额和使用量
searchFiles, // 搜索与过滤文件/目录
copyFile, // 复制文件
copyDirectory, // 复制目录
resetClient, // 重置 SDK Client 实例(支持按 spaceId 重置)
renewTokenViaSdk, // 通过 SDK 续期 Token(降级方案)
// ---- 回收站 API ----
getRecycleList, // 获取回收站列表(分页)
recycleRestore, // 恢复回收站项目
recycleRestoreBatch, // 批量恢复回收站项目
recyclePurge, // 永久删除回收站项目
recyclePurgeBatch, // 批量永久删除回收站项目
recycleEmpty, // 清空回收站
} from 'smh-web-uikit'仅使用服务层(自定义 UI)
如果你希望完全自定义 UI 界面,只使用 smh-web-uikit 提供的服务层能力(Token 管理 + 文件操作 API),可以跳过 <SpaceDrive /> 组件,直接调用底层服务函数。
服务层不依赖任何 UI 组件(无 React、无 TDesign 依赖),可以在任意前端框架中使用。
接入步骤
1. 初始化配置 & Token
在应用启动时,调用 setSmhConfig 设置 SMH 连接参数,然后调用 initToken 完成首次 Token 获取:
import {
setSmhConfig,
initToken,
clearConfig,
} from 'smh-web-uikit'
// 1. 设置配置
setSmhConfig({
basePath: 'https://api.tencentsmh.cn',
libraryId: 'smhxxx-xxxxx',
spaceId: 'spaceyyyyyy',
getAccessToken: async () => {
const res = await fetch('/api/your-backend/generate-space-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ spaceId: 'spaceyyyyyy' }),
})
const data = await res.json()
return { accessToken: data.accessToken, expiresAt: data.expiresAt }
},
// 可选:自定义错误提示(不传则静默,仅 throw Error)
onError: ({ message }) => {
// 替换为你自己的 UI 提示方式,如 antd message、Element Plus ElMessage 等
console.error('[SMH Error]', message)
},
})
// 2. 初始化 Token(必须在调用任何文件操作 API 之前完成)
await initToken()
// 3. 应用卸载时清理
// clearConfig()2. 调用文件操作 API
初始化完成后,直接 import 服务层的文件操作函数即可使用。所有 API 内部会自动管理 Token 续期,调用方无需关心 Token 生命周期。
import {
getFileList,
uploadFile,
delFile,
delDirectory,
createDirectory,
moveFile,
moveDirectory,
renameFile,
renameDirectory,
getPreview,
getDocPreviewUrl,
downloadFile,
getFileInfo,
getFilePreviewUrlOrContent,
getSpaceUsage,
searchFiles,
resetClient,
// 回收站
getRecycleList,
recycleRestore,
recycleRestoreBatch,
recyclePurge,
recyclePurgeBatch,
recycleEmpty,
} from 'smh-web-uikit'所有 API 均从
smh-web-uikit统一导入。
服务层 API 一览
配置与 Token 管理(smh-web-uikit)
| 函数 | 说明 | 调用时机 |
|------|------|----------|
| setSmhConfig(config) | 设置 SMH 连接配置 | 应用启动时,必须最先调用 |
| initToken() | 初始化 Token(首次获取) | 应用启动时,setSmhConfig 之后调用 |
| ensureValidToken() | 确保 Token 有效,自动续期 | 一般无需手动调用,文件操作 API 内部已自动调用 |
| isTokenExpiringSoon() | 检查 Token 是否即将过期(5 分钟内) | 需要自行实现定时续期逻辑时使用 |
| isTokenExpired() | 检查 Token 是否已过期 | 需要判断 Token 状态时使用 |
| getAccessToken() | 获取当前 accessToken 字符串 | 需要手动拼接请求时使用 |
| getTokenExpireInfo() | 获取 Token 过期时间信息 | 需要展示 Token 状态时使用 |
| getLibraryId() | 获取当前 libraryId | 需要手动拼接请求时使用 |
| getSpaceId() | 获取当前 spaceId | 需要手动拼接请求时使用 |
| getBasePath() | 获取当前 basePath | 需要手动拼接请求时使用 |
| clearConfig() | 清除所有配置和 Token(包括所有 space 的缓存) | 应用卸载 / 切换用户时调用 |
| clearSpaceCache(spaceId?) | 清除指定 space 的 Token 缓存,不传则清除当前 space | 需要强制刷新某个 space 的 Token 时使用 |
文件操作 API(smh-web-uikit)
| 函数 | 说明 | 典型场景 |
|------|------|----------|
| getFileList(dirPath, { page, pageSize }) | 获取目录下的文件列表(分页) | 文件列表页、目录浏览 |
| uploadFile(file, filePath, callbacks) | 上传文件(支持分片、断点续传、秒传) | 文件上传功能 |
| delFile(filePath) | 删除单个文件 | 文件删除操作 |
| delDirectory(dirPath) | 删除目录 | 目录删除操作 |
| createDirectory(dirPath) | 创建文件夹 | 新建文件夹功能 |
| moveFile(fromPath, toPath) | 移动文件到目标路径 | 文件移动 / 整理 |
| moveDirectory(fromPath, toPath) | 移动目录到目标路径 | 目录移动 / 整理 |
| renameFile(oldPath, newPath) | 重命名文件 | 文件重命名 |
| renameDirectory(oldPath, newPath) | 重命名目录 | 目录重命名 |
| getFileInfo(filePath) | 获取文件详情信息 | 文件详情页、属性面板 |
| getPreview(filePath, isDoc?) | 获取文件预览地址或内容 | 图片/视频预览、文档内容读取 |
| getDocPreviewUrl(filePath) | 获取文档在线预览 URL | iframe 嵌入预览 Office 文档 |
| downloadFile(filePath, fileName?) | 下载文件(触发浏览器原生下载) | 文件下载功能 |
| getFilePreviewUrlOrContent(file) | 根据文件类型自动获取预览链接或内容 | 通用预览(自动判断图片/视频/文档) |
| getSpaceUsage() | 获取空间配额和已用容量 | 存储用量展示、容量告警 |
| searchFiles(options) | 搜索与过滤文件/目录(支持关键字、类型、后缀、大小、时间等) | 文件搜索、高级过滤 |
| resetClient(spaceId?) | 重置内部 SDK Client 实例,传 spaceId 则重置指定 space,不传则重置所有 | 配置变更后调用(切换空间时无需手动调用,内部自动缓存复用) |
| renewTokenViaSdk() | 通过 SDK API 续期当前 Token(降级方案,不依赖 getAccessToken) | Token 续期降级场景 |
| getRecycleList(options) | 获取回收站列表(分页),支持按删除时间、名称、大小排序 | 回收站页面展示 |
| recycleRestore(recycledItemId) | 恢复单个回收站项目到原始路径(路径不存在回退到根目录) | 单个文件恢复 |
| recycleRestoreBatch(ids) | 批量恢复回收站项目 | 批量恢复 |
| recyclePurge(recycledItemId) | 永久删除单个回收站项目 | 单个永久删除 |
| recyclePurgeBatch(ids) | 批量永久删除回收站项目 | 批量永久删除 |
| recycleEmpty() | 清空回收站所有项目 | 一键清空回收站 |
完整示例:Vue 3 中使用服务层
以下示例展示在 Vue 3 项目中,仅使用服务层构建自定义文件管理界面:
<template>
<div class="file-manager">
<div class="toolbar">
<button @click="handleCreateFolder">新建文件夹</button>
<input type="file" @change="handleUpload" />
<span>已用: {{ formatSize(usage.used) }} / {{ formatSize(usage.total) }}</span>
</div>
<ul class="file-list">
<li v-for="file in files" :key="file.name" @click="handleOpen(file)">
<span>{{ file.type === 'dir' ? '📁' : '📄' }} {{ file.name }}</span>
<button @click.stop="handleDelete(file)">删除</button>
<button @click.stop="handleDownload(file)" v-if="file.type !== 'dir'">下载</button>
</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import {
setSmhConfig, initToken, clearConfig,
isTokenExpiringSoon, ensureValidToken,
getFileList, uploadFile, delFile, delDirectory,
createDirectory, downloadFile, getSpaceUsage,
} from 'smh-web-uikit'
const files = ref([])
const currentPath = ref('')
const usage = ref({ used: 0, total: 0 })
// 初始化
onMounted(async () => {
setSmhConfig({
basePath: 'https://api.tencentsmh.cn',
libraryId: 'smhxxx-xxxxx',
spaceId: 'spaceyyyyyy',
getAccessToken: async () => {
const res = await fetch('/api/generate-space-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ spaceId: 'spaceyyyyyy' }),
})
const data = await res.json()
return { accessToken: data.accessToken, expiresAt: data.expiresAt }
},
onError: ({ message }) => ElMessage.error(message), // Element Plus 提示
})
await initToken()
await loadFiles()
const usageData = await getSpaceUsage()
if (usageData) usage.value = usageData
})
// Token 定时续期
const timer = setInterval(() => {
if (isTokenExpiringSoon()) ensureValidToken().catch(() => {})
}, 30 * 1000)
onUnmounted(() => {
clearInterval(timer)
clearConfig()
})
// 加载文件列表
async function loadFiles() {
const data = await getFileList(currentPath.value, { page: 1, pageSize: 100 })
files.value = data.contents || []
}
// 新建文件夹
async function handleCreateFolder() {
const name = prompt('请输入文件夹名称')
if (!name) return
const path = currentPath.value ? `${currentPath.value}/${name}` : name
await createDirectory(path)
await loadFiles()
}
// 上传文件
async function handleUpload(e) {
const file = e.target.files[0]
if (!file) return
const filePath = currentPath.value ? `${currentPath.value}/${file.name}` : file.name
await uploadFile(file, filePath, {
onProgressCallback: (percent) => console.log(`上传进度: ${percent}%`),
onSuccessCallback: () => loadFiles(),
onErrorCallback: () => console.error('上传失败'),
})
}
// 删除
async function handleDelete(file) {
if (file.type === 'dir') {
await delDirectory(currentPath.value ? `${currentPath.value}/${file.name}` : file.name)
} else {
await delFile(currentPath.value ? `${currentPath.value}/${file.name}` : file.name)
}
await loadFiles()
}
// 下载
async function handleDownload(file) {
const filePath = currentPath.value ? `${currentPath.value}/${file.name}` : file.name
await downloadFile(filePath, file.name)
}
function formatSize(bytes) {
if (!bytes) return '0 B'
const units = ['B', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(1024))
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + units[i]
}
</script>自行管理 Token 续期
当你不使用 <SpaceDrive /> 组件时,需要自行实现 Token 定时续期。推荐方式:
import { isTokenExpiringSoon, ensureValidToken } from 'smh-web-uikit'
// 每 30 秒检查一次,即将过期时自动续期
const timer = setInterval(() => {
if (isTokenExpiringSoon()) {
ensureValidToken().catch(err => console.error('Token 续期失败:', err))
}
}, 30 * 1000)
// 应用卸载时清理
clearInterval(timer)
<SpaceDrive />组件内部已内置此逻辑,使用组件时无需手动处理。
服务层 API 详细说明
以下是每个文件操作 API 的详细参数签名、返回值和使用示例。
getFileList(dirPath, options) — 获取文件列表
function getFileList(
dirPath?: string, // 目录路径,空字符串表示根目录
options?: { page?: number, pageSize?: number } // 分页参数,默认 page=1, pageSize=100
): Promise<{
contents: Array<{ // 文件/目录列表
name: string // 文件名
type: 'file' | 'dir' // 类型
size?: number // 文件大小(字节),目录无此字段
creationTime?: string // 创建时间
modificationTime?: string // 修改时间
// ...其他 SMH 返回字段
}>
totalNum: number // 总条数
hasMore: boolean // 是否有更多
}>示例:
// 获取根目录第一页
const data = await getFileList('', { page: 1, pageSize: 50 })
console.log(data.contents) // 文件列表
console.log(data.totalNum) // 总数
// 获取子目录
const subData = await getFileList('docs/reports', { page: 1, pageSize: 100 })uploadFile(file, filePath, callbacks) — 上传文件
支持分片上传、断点续传、秒传检测。如果目标目录不存在,会自动创建。
function uploadFile(
file: File, // 浏览器 File 对象
filePath: string, // 上传目标路径,如 'docs/report.pdf'
callbacks?: {
onProgressCallback?: (percent: number, speed: number) => void // 进度回调,percent 为 0-100,speed 单位 B/s
onSuccessCallback?: (result: { id: string, name: string }) => void // 上传成功回调
onErrorCallback?: (error: any) => void // 上传失败回调
onStateChangeCallback?: (state: string) => void // 状态变更回调(如 'computing_hash' 秒传校验中)
}
): Promise<object> // 返回上传 checkpoint 信息示例:
// 基础上传
await uploadFile(fileObject, 'docs/hello.pdf')
// 带进度回调的上传
await uploadFile(fileObject, 'images/photo.jpg', {
onProgressCallback: (percent, speed) => {
console.log(`进度: ${percent}%, 速度: ${(speed / 1024).toFixed(1)} KB/s`)
},
onSuccessCallback: ({ id, name }) => {
console.log(`上传成功: ${name}`)
},
onErrorCallback: (err) => {
console.error('上传失败:', err)
},
onStateChangeCallback: (state) => {
if (state === 'computing_hash') console.log('正在校验秒传...')
},
})delFile(filePath) — 删除文件
function delFile(filePath: string | string[]): Promise<boolean> // 返回是否删除成功示例:
const success = await delFile('docs/old-report.pdf')
// 也支持数组形式的路径
const success2 = await delFile(['docs', 'old-report.pdf'])delDirectory(dirPath) — 删除目录
function delDirectory(dirPath: string | string[]): Promise<boolean> // 返回是否删除成功示例:
const success = await delDirectory('docs/archive')createDirectory(dirPath) — 创建文件夹
如果同名目录已存在,会自动重命名(追加后缀)。
function createDirectory(dirPath: string | string[]): Promise<object> // 返回创建结果示例:
await createDirectory('docs/new-folder')moveFile(fromPath, toPath) — 移动文件
将文件从一个路径移动到另一个路径。如果目标路径已存在同名文件,会自动重命名。
function moveFile(
fromPath: string | string[], // 原文件路径
toPath: string | string[] // 目标文件路径
): Promise<object>示例:
// 将文件从根目录移动到 docs 目录
await moveFile('report.pdf', 'docs/report.pdf')
// 数组形式
await moveFile(['uploads', 'photo.jpg'], ['images', 'photo.jpg'])moveDirectory(fromPath, toPath) — 移动目录
将目录从一个路径移动到另一个路径。如果目标路径已存在同名目录,会自动重命名。
function moveDirectory(
fromPath: string | string[], // 原目录路径
toPath: string | string[] // 目标目录路径
): Promise<object>示例:
await moveDirectory('temp/drafts', 'docs/drafts')renameFile(oldPath, newPath) — 重命名文件
通过移动操作实现重命名。如果目标路径已存在同名文件,会提示冲突(conflictResolutionStrategy: 'ask')。
function renameFile(
oldPath: string | string[], // 原文件路径
newPath: string | string[] // 新文件路径
): Promise<object>示例:
await renameFile('docs/old-name.pdf', 'docs/new-name.pdf')renameDirectory(oldPath, newPath) — 重命名目录
function renameDirectory(
oldPath: string | string[], // 原目录路径
newPath: string | string[] // 新目录路径
): Promise<object>示例:
await renameDirectory('docs/old-folder', 'docs/new-folder')getFileInfo(filePath) — 获取文件详情
function getFileInfo(filePath: string | string[]): Promise<{
name: string
type: 'file' | 'dir'
size?: number
creationTime?: string
modificationTime?: string
// ...其他 SMH 返回字段
}>示例:
const info = await getFileInfo('docs/report.pdf')
console.log(`文件大小: ${info.size} 字节`)getPreview(filePath, isDoc?) — 获取预览地址或内容
根据文件类型返回不同结果:
- 图片/视频:返回带
accessToken的直连 URL(字符串) - 文档(
isDoc=true):获取文件的cosUrl并返回文本内容
function getPreview(
filePath: string | string[], // 文件路径
isDoc?: boolean // 是否为文档类型,默认 false
): Promise<string | object> // 图片/视频返回 URL 字符串,文档返回文本内容示例:
// 图片预览 URL
const imgUrl = await getPreview('images/photo.jpg')
img.src = imgUrl
// 文档内容
const textContent = await getPreview('docs/readme.md', true)
console.log(textContent)getDocPreviewUrl(filePath) — 获取文档在线预览 URL
返回文档的 cosUrl,可用于 iframe 嵌入在线预览 Office 文档。
function getDocPreviewUrl(filePath: string | string[]): Promise<string> // cosUrl示例:
const previewUrl = await getDocPreviewUrl('docs/report.docx')
// 在 iframe 中预览
iframe.src = previewUrldownloadFile(filePath, fileName?) — 下载文件
通过 SDK 的 downloadByUrl 方法获取文件的 cosUrl,并通过 <a> 标签触发浏览器原生下载。
function downloadFile(
filePath: string | string[], // 文件路径
fileName?: string // 自定义保存文件名,不传则使用远端文件名
): Promise<void>示例:
// 使用原始文件名下载
await downloadFile('docs/report.pdf')
// 自定义下载文件名
await downloadFile('docs/report.pdf', '2024年度报告.pdf')getFilePreviewUrlOrContent(file) — 自动获取预览
根据文件扩展名自动判断类型,调用对应的预览方法:
- 图片/视频(jpg、png、gif、mp4 等)→ 返回预览 URL
- 文档/文本(json、txt、md、log、docx)→ 返回文本内容
- 其他类型 → 返回预览 URL
function getFilePreviewUrlOrContent(file: {
name: string // 文件名(用于判断扩展名)
path?: string[] // 文件路径数组
}): Promise<string>示例:
const result = await getFilePreviewUrlOrContent({
name: 'photo.jpg',
path: ['images', 'photo.jpg'],
})getSpaceUsage() — 获取空间使用量
function getSpaceUsage(): Promise<{
used: number // 已使用容量(字节)
total: number // 总配额(字节)
} | null> // 获取失败返回 null示例:
const usage = await getSpaceUsage()
if (usage) {
const usedGB = (usage.used / 1024 / 1024 / 1024).toFixed(2)
const totalGB = (usage.total / 1024 / 1024 / 1024).toFixed(2)
console.log(`已用 ${usedGB} GB / 共 ${totalGB} GB`)
}searchFiles(options) — 搜索与过滤文件/目录
基于 smh-js-sdk 的 client.search.searchFs 接口,支持多维度搜索与过滤。
注意:该接口 QPS 上限为 10,不适用于高频操作场景(如首页列表查询)。
function searchFiles(options?: {
keywords?: string[] // 搜索关键字数组,如 ['身份证', '中国'](多个为或关系)
extname?: string[] // 文件后缀过滤(带点号),如 ['.png', '.jpg']
excludeExtName?: string[] // 排除的文件后缀(带点号),如 ['.xls', '.xlsx']
fileType?: Array<'file' | 'dir' | 'symlink'> // 文件类型数组
minFileSize?: number // 最小文件大小(Byte)
maxFileSize?: number // 最大文件大小(Byte)
modificationTimeStart?: string // 修改时间起始(ISO 8601)
modificationTimeEnd?: string // 修改时间截止(ISO 8601)
orderBy?: 'name' | 'modificationTime' | 'size' | 'creationTime' | 'localCreationTime' | 'localModificationTime' // 排序字段
orderByType?: 'asc' | 'desc' // 排序方式
labels?: string[] // 文件标签过滤
categories?: string[] // 文件分类过滤
limit?: number // 每页数量,默认 50,范围 [1, 100]
marker?: string // 分页标识(用于翻页)
dirPath?: string // 目录路径过滤,仅返回该目录下的文件,如 'folderA/subFolder'
}): Promise<{
contents: Array<{ // 搜索结果列表
type: string // 条目类型:dir / file / image / video / symlink
inode: string // 文件目录 ID
name: string // 文件名或目录名
path: string[] // 文件路径数组,如 ['folderA', '1.jpg'](通过 inode 接口自动补全)
size: string // 文件大小(字符串格式,单位 Byte)
creationTime: string // 创建时间(ISO 8601)
modificationTime: string // 修改时间(ISO 8601)
contentType: string // 媒体类型
// ... 更多字段见 SDK 文档
}>
nextMarker: string | undefined // 下一页标识,为空表示已到最后一页
}>说明:搜索接口原始返回结果中不包含文件夹路径信息,
searchFiles内部会自动通过GET /api/v1/inode/{LibraryId}/{SpaceId}/{Inode}接口为每个结果补全path数组,因此调用方无需额外处理。目录过滤:传入
dirPath后,会在补全path之后进行前缀匹配过滤,仅保留该目录下的文件。注意这是客户端过滤,不影响 API 请求本身,因此返回的contents数量可能少于limit。
示例 — 关键字搜索:
// 搜索包含 "报告" 的文件
const result = await searchFiles({ keywords: ['报告'] })
console.log(`找到 ${result.contents.length} 个结果`)
result.contents.forEach(item => {
const folder = item.path.slice(0, -1).join('/') || '根目录'
console.log(`${item.type === 'dir' ? '📁' : '📄'} ${item.name} (位于: ${folder})`)
})示例 — 多条件过滤:
// 搜索最近 7 天内修改的 PDF 和 DOCX 文件,按修改时间倒序
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 3600 * 1000).toISOString()
const result = await searchFiles({
extname: ['.pdf', '.docx'],
fileType: ['file'],
modificationTimeStart: sevenDaysAgo,
orderBy: 'modificationTime',
orderByType: 'desc',
limit: 20,
})示例 — 文件大小过滤:
// 搜索大于 10MB 的文件
const result = await searchFiles({
fileType: ['file'],
minFileSize: 10 * 1024 * 1024,
orderBy: 'size',
orderByType: 'desc',
})示例 — 目录过滤:
// 仅搜索 'documents/reports' 目录下包含 "季度" 的文件
const result = await searchFiles({
keywords: ['季度'],
dirPath: 'documents/reports',
})
console.log(`在 documents/reports 下找到 ${result.contents.length} 个结果`)示例 — 分页加载:
// 首次搜索
let result = await searchFiles({ keywords: ['图片'], limit: 20 })
let allResults = [...result.contents]
// 翻页加载更多
while (result.nextMarker) {
result = await searchFiles({
keywords: ['图片'],
limit: 20,
marker: result.nextMarker,
})
allResults.push(...result.contents)
}
console.log(`共找到 ${allResults.length} 个结果`)resetClient(spaceId?) — 重置 SDK Client
重置内部的 SMHClient 实例。传入 spaceId 则只重置指定 space 的 client,不传则重置所有 space 的 client。
注意:切换空间时无需手动调用
resetClient(),内部已自动按 spaceId 缓存和复用 client。仅在basePath、libraryId等全局配置变更时才需要调用。
function resetClient(spaceId?: string): void示例:
// 重置指定 space 的 client
resetClient('space-xxxxx')
// 重置所有 space 的 client(全局配置变更时)
resetClient()renewTokenViaSdk() — 通过 SDK 续期 Token
通过 SMH API POST /api/v1/token/{LibraryId}/{AccessToken} 续期当前 Token。这是一个降级方案,当未提供 getAccessToken 回调时,ensureValidToken 内部会自动尝试调用此方法续期。
⚠️ 该方法依赖当前 Token 尚未完全过期,且续期时长固定为创建 Token 时指定的
Period。推荐优先使用getAccessToken回调方式续期。
function renewTokenViaSdk(): Promise<{
accessToken: string // 续期后的新 Token
expiresAt: number // 新的过期时间(毫秒级时间戳)
}>示例:
import { renewTokenViaSdk } from 'smh-web-uikit'
try {
const { accessToken, expiresAt } = await renewTokenViaSdk()
console.log('续期成功,新 Token 过期时间:', new Date(expiresAt))
} catch (err) {
console.error('续期失败:', err.message)
}getRecycleList(options) — 获取回收站列表
function getRecycleList(options?: {
page?: number // 分页码,默认 1
pageSize?: number // 分页大小,默认 20
orderBy?: string // 排序字段:'name' | 'modificationTime' | 'size' | 'removalTime' | 'remainingTime'
orderByType?: string // 排序方式:'asc' | 'desc',默认 'desc'
}): Promise<{
contents: Array<{
recycledItemId: number // 回收站项目 ID(用于恢复/删除操作)
name: string // 文件名
type: string // 类型:'file' | 'dir'
size?: number // 文件大小(字节)
path?: string[] // 原始路径数组
removalTime?: string // 删除时间(ISO 8601)
remainingTime?: number // 剩余保留时间(秒)
}>
totalNum: number // 总条数
}>示例:
// 获取回收站列表,按删除时间倒序
const data = await getRecycleList({ page: 1, pageSize: 20 })
console.log(`回收站共 ${data.totalNum} 项`)
data.contents.forEach(item => {
const days = Math.ceil(item.remainingTime / 86400)
console.log(`${item.name} — 剩余 ${days} 天`)
})recycleRestore(recycledItemId) — 恢复回收站项目
恢复到原始路径,路径不存在时回退到根目录。冲突时自动重命名。
function recycleRestore(recycledItemId: number): Promise<object>示例:
await recycleRestore(12345) // 恢复 ID 为 12345 的回收站项目recycleRestoreBatch(ids) — 批量恢复回收站项目
function recycleRestoreBatch(ids: number[]): Promise<object>示例:
await recycleRestoreBatch([12345, 12346, 12347])recyclePurge(recycledItemId) — 永久删除回收站项目
永久删除后不可恢复。
function recyclePurge(recycledItemId: number): Promise<void>示例:
await recyclePurge(12345)recyclePurgeBatch(ids) — 批量永久删除回收站项目
function recyclePurgeBatch(ids: number[]): Promise<void>示例:
await recyclePurgeBatch([12345, 12346, 12347])recycleEmpty() — 清空回收站
清空回收站内所有项目,操作不可恢复。清空操作异步执行,调用后回收站立即不可见。
function recycleEmpty(): Promise<void>示例:
await recycleEmpty()两种接入方式对比
| | 使用 <SpaceDrive /> 组件 | 仅使用服务层 |
|---|---|---|
| 适用场景 | 快速接入,使用现成 UI(可选简洁/完整两种风格) | 需要完全自定义 UI 风格 |
| UI 框架 | 必须使用 React | 任意框架(Vue、Angular、Svelte 等) |
| UI 模式 | 通过 uiMode 切换:'compact'(简洁)/ 'full'(完整) | 自行实现 |
| Token 续期 | 自动(组件内置) | 需自行实现定时检查 |
| 错误提示 | 自动(内置 Toast) | 通过 onError 回调自定义 |
| 需要引入样式 | 是(style.css) | 否 |
| 代码量 | 最少,几行即可 | 较多,需自行构建 UI |
Token 自动续期机制
UIKit 内部实现了完整的 token 自动续期机制,接入方无需手动管理 token 生命周期:
时间线:
0h 1h55m 2h
|------- 正常使用 token ---------|--- 检测到即将过期 ---|--- 旧 token 过期 ---|
↓
自动调用 getAccessToken()
获取新 token,无缝续期- 检查频率:每 30 秒检查一次 token 状态
- 提前续期:在 token 过期前 5 分钟触发续期
- 并发保护:多个请求同时发现 token 过期时,只会触发一次续期(按 spaceId 隔离)
- 请求级保护:每次 API 请求前都会检查 token 有效性
- 缓存池机制:每个 space 的 token 独立缓存,切换 space 时自动保存和恢复,缓存中过期的 token 会自动触发续期
- 过期安全:如果
getAccessToken返回的expiresAt已过期或无法解析,自动使用默认有效期(2小时)兜底 - 时间格式兼容:
expiresAt支持毫秒/秒级时间戳、ISO 8601 字符串(含纳秒精度)、Date 对象,SDK 内部自动转换
切换空间
当需要切换到不同的 spaceId 时,UIKit 内部采用 Token 缓存池 + Client 缓存池 机制自动处理:
- 检测到
spaceId变化后,先将当前 space 的 token 保存到缓存池 - 尝试从缓存池恢复目标 space 的 token 和 client(如果之前访问过)
- 如果缓存中没有目标 space 的 token,或缓存的 token 已过期,自动调用
getAccessToken获取新 token - 无需手动调用
resetClient(),client 按 spaceId 自动缓存和复用
性能优势:频繁在多个 space 之间切换时,已访问过的 space 可以直接从缓存恢复,无需重新获取 token 和重建 client,大幅减少网络请求。
接入方只需更新传入的 spaceId prop 即可:
<SpaceDrive
basePath={basePath}
libraryId={libraryId}
spaceId={currentSpaceId} // 切换此值即可,内部自动缓存和恢复
getAccessToken={getAccessToken}
/>💡 缓存安全性:即使缓存中的 token 已过期,
ensureValidToken()会在每次 API 请求前自动检测并触发续期,不会导致请求失败。
手动清除缓存
如果需要强制刷新某个 space 的 token(例如权限变更后),可以使用 clearSpaceCache:
import { clearSpaceCache } from 'smh-web-uikit'
// 清除指定 space 的缓存
clearSpaceCache('space-xxxxx')
// 清除当前 space 的缓存
clearSpaceCache()样式引入
UIKit 的样式需要在宿主项目中手动引入:
// 在入口文件中引入
import 'smh-web-uikit/dist/style.css'UIKit 内部所有 UI 均为原生实现,不依赖第三方 UI 组件库。
注意事项
librarySecret绝不能暴露给前端,token 的生成必须在后端完成getAccessToken函数引用需保持稳定,建议使用useCallback包裹或定义在组件外部,避免不必要的重新初始化- 组件销毁时调用
clearConfig(),清理内部状态(包括所有 space 的 token 和 client 缓存),防止内存泄漏和状态残留 expiresAt支持多种时间格式:毫秒时间戳、秒级时间戳、ISO 8601 字符串(含纳秒精度)、Date 对象,SDK 内部会自动统一转换- 组件默认占满父容器的
100%高度,请确保父容器有合适的高度约束 - 切换空间无需手动
resetClient(),内部按 spaceId 自动缓存 token 和 client,切换时自动恢复。如需强制刷新某个 space 的 token,使用clearSpaceCache(spaceId)
相关 SDK 文档
| SDK | npm 包名 | 说明 |
|-----|---------|------|
| 前端 SDK | smh-js-sdk | 前端直连 SMH API,UIKit 内部已集成 |
| 后端 SDK | smh-node-sdk | 后端管理 API,接入方需在后端安装使用 |
更多 SMH 服务信息请参考 腾讯云智能媒体托管文档
