462 lines
16 KiB
Markdown
462 lines
16 KiB
Markdown
|
|
# 统一API接口设计文档
|
|||
|
|
|
|||
|
|
## 1. 概述
|
|||
|
|
|
|||
|
|
### 1.1 目标
|
|||
|
|
|
|||
|
|
为iframe中的第三方应用提供一套统一、简洁、类型安全的系统服务访问接口,使应用开发者无需关注底层通信机制,即可直接调用系统功能。
|
|||
|
|
|
|||
|
|
### 1.2 核心价值
|
|||
|
|
|
|||
|
|
- **简化开发**:封装复杂的跨域通信逻辑,提供类似本地函数调用的体验
|
|||
|
|
- **类型安全**:完整的TypeScript类型定义,提供编译时检查和IDE智能提示
|
|||
|
|
- **模块化设计**:按功能划分子模块,便于按需使用和维护
|
|||
|
|
- **权限控制**:内置权限验证机制,确保系统安全
|
|||
|
|
- **事件驱动**:支持双向通信,实现系统与应用间的实时交互
|
|||
|
|
|
|||
|
|
### 1.3 设计原则
|
|||
|
|
|
|||
|
|
1. **透明性**:隐藏底层postMessage通信细节
|
|||
|
|
2. **一致性**:统一的API响应格式和错误处理机制
|
|||
|
|
3. **可扩展性**:模块化架构支持功能扩展
|
|||
|
|
4. **安全性**:严格的权限控制和数据验证
|
|||
|
|
|
|||
|
|
## 2. 系统架构
|
|||
|
|
|
|||
|
|
### 2.1 整体架构图
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "主应用(系统)"
|
|||
|
|
A[主应用UI] --> B[沙箱引擎]
|
|||
|
|
B --> C[事件通信服务]
|
|||
|
|
C --> D[系统服务层]
|
|||
|
|
D --> E[窗口管理]
|
|||
|
|
D --> F[存储服务]
|
|||
|
|
D --> G[网络服务]
|
|||
|
|
D --> H[系统服务]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph "子应用(沙箱)"
|
|||
|
|
I[子应用UI] --> J[SDK客户端]
|
|||
|
|
K[业务逻辑] --> J
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
J --"postMessage"--> B
|
|||
|
|
B --"postMessage"--> J
|
|||
|
|
|
|||
|
|
style A fill:#e1f5fe
|
|||
|
|
style I fill:#f3e5f5
|
|||
|
|
style J fill:#f3e5f5
|
|||
|
|
style B fill:#fff3e0
|
|||
|
|
style C fill:#fff3e0
|
|||
|
|
style D fill:#f1f8e9
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 SDK架构
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
classDiagram
|
|||
|
|
class SystemDesktopSDK {
|
|||
|
|
+version: string
|
|||
|
|
+appId: string
|
|||
|
|
+initialized: boolean
|
|||
|
|
+window: WindowSDK
|
|||
|
|
+storage: StorageSDK
|
|||
|
|
+network: NetworkSDK
|
|||
|
|
+events: EventSDK
|
|||
|
|
+ui: UISDK
|
|||
|
|
+system: SystemSDK
|
|||
|
|
+init(config: SDKConfig) Promise~APIResponse~boolean~~
|
|||
|
|
+destroy() Promise~APIResponse~boolean~~
|
|||
|
|
+getStatus() Promise~APIResponse~object~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class SDKBase {
|
|||
|
|
#appId: string
|
|||
|
|
#initialized: boolean
|
|||
|
|
#sendToSystem(type: string, data: any) Promise~T~
|
|||
|
|
#wrapResponse(promise: Promise~T~) Promise~APIResponse~T~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class WindowSDK {
|
|||
|
|
<<interface>>
|
|||
|
|
+setTitle(title: string) Promise~APIResponse~boolean~~
|
|||
|
|
+resize(width: number, height: number) Promise~APIResponse~boolean~~
|
|||
|
|
+move(x: number, y: number) Promise~APIResponse~boolean~~
|
|||
|
|
+minimize() Promise~APIResponse~boolean~~
|
|||
|
|
+maximize() Promise~APIResponse~boolean~~
|
|||
|
|
+restore() Promise~APIResponse~boolean~~
|
|||
|
|
+close() Promise~APIResponse~boolean~~
|
|||
|
|
+getState() Promise~APIResponse~WindowState~~
|
|||
|
|
+on(event: string, callback: Function) void
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class StorageSDK {
|
|||
|
|
<<interface>>
|
|||
|
|
+set(key: string, value: any) Promise~APIResponse~boolean~~
|
|||
|
|
+get(key: string) Promise~APIResponse~any~~
|
|||
|
|
+remove(key: string) Promise~APIResponse~boolean~~
|
|||
|
|
+clear() Promise~APIResponse~boolean~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class NetworkSDK {
|
|||
|
|
<<interface>>
|
|||
|
|
+request(url: string, config: NetworkRequestConfig) Promise~APIResponse~any~~
|
|||
|
|
+get(url: string, config: any) Promise~APIResponse~any~~
|
|||
|
|
+post(url: string, data: any, config: any) Promise~APIResponse~any~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class EventSDK {
|
|||
|
|
<<interface>>
|
|||
|
|
+emit(channel: string, data: any) Promise~APIResponse~string~~
|
|||
|
|
+on(channel: string, callback: Function) Promise~APIResponse~string~~
|
|||
|
|
+off(subscriptionId: string) Promise~APIResponse~boolean~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class UISDK {
|
|||
|
|
<<interface>>
|
|||
|
|
+showDialog(options: DialogOptions) Promise~APIResponse~object~~
|
|||
|
|
+showNotification(options: NotificationOptions) Promise~APIResponse~string~~
|
|||
|
|
+showToast(message: string, type: string) Promise~APIResponse~string~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class SystemSDK {
|
|||
|
|
<<interface>>
|
|||
|
|
+getSystemInfo() Promise~APIResponse~SystemInfo~~
|
|||
|
|
+getAppInfo() Promise~APIResponse~AppInfo~~
|
|||
|
|
+requestPermission(permission: string) Promise~APIResponse~PermissionStatus~~
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SDKBase <|-- SystemDesktopSDK
|
|||
|
|
SystemDesktopSDK --> WindowSDK
|
|||
|
|
SystemDesktopSDK --> StorageSDK
|
|||
|
|
SystemDesktopSDK --> NetworkSDK
|
|||
|
|
SystemDesktopSDK --> EventSDK
|
|||
|
|
SystemDesktopSDK --> UISDK
|
|||
|
|
SystemDesktopSDK --> SystemSDK
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 3. 核心模块设计
|
|||
|
|
|
|||
|
|
### 3.1 窗口管理模块(WindowSDK)
|
|||
|
|
|
|||
|
|
#### 3.1.1 功能概述
|
|||
|
|
|
|||
|
|
提供对应用窗口的控制能力,包括窗口尺寸调整、位置移动、状态切换等。
|
|||
|
|
|
|||
|
|
#### 3.1.2 接口定义
|
|||
|
|
|
|||
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|||
|
|
| --------------------- | ------------ | ----------------------------- | --------------------------------- |
|
|||
|
|
| setTitle(title) | 设置窗口标题 | title: string | Promise<APIResponse<boolean>> |
|
|||
|
|
| resize(width, height) | 调整窗口尺寸 | width: number, height: number | Promise<APIResponse<boolean>> |
|
|||
|
|
| move(x, y) | 移动窗口位置 | x: number, y: number | Promise<APIResponse<boolean>> |
|
|||
|
|
| minimize() | 最小化窗口 | 无 | Promise<APIResponse<boolean>> |
|
|||
|
|
| maximize() | 最大化窗口 | 无 | Promise<APIResponse<boolean>> |
|
|||
|
|
| restore() | 还原窗口 | 无 | Promise<APIResponse<boolean>> |
|
|||
|
|
| close() | 关闭窗口 | 无 | Promise<APIResponse<boolean>> |
|
|||
|
|
| getState() | 获取窗口状态 | 无 | Promise<APIResponse<WindowState>> |
|
|||
|
|
|
|||
|
|
#### 3.1.3 事件监听
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 监听窗口变化事件
|
|||
|
|
SystemSDK.window.on('resize', (width, height) => {
|
|||
|
|
console.log(`窗口尺寸变化: ${width}x${height}`)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 移除事件监听
|
|||
|
|
SystemSDK.window.off('resize')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 存储模块(StorageSDK)
|
|||
|
|
|
|||
|
|
#### 3.2.1 功能概述
|
|||
|
|
|
|||
|
|
提供应用数据的持久化存储能力,支持键值对存储、数据查询、删除等操作。
|
|||
|
|
|
|||
|
|
#### 3.2.2 接口定义
|
|||
|
|
|
|||
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|||
|
|
| --------------- | -------------- | ----------------------- | ------------------------------ |
|
|||
|
|
| set(key, value) | 存储数据 | key: string, value: any | Promise<APIResponse<boolean>> |
|
|||
|
|
| get(key) | 获取数据 | key: string | Promise<APIResponse<any>> |
|
|||
|
|
| remove(key) | 删除数据 | key: string | Promise<APIResponse<boolean>> |
|
|||
|
|
| clear() | 清空所有数据 | 无 | Promise<APIResponse<boolean>> |
|
|||
|
|
| keys() | 获取所有键名 | 无 | Promise<APIResponse<string[]>> |
|
|||
|
|
| has(key) | 检查键是否存在 | key: string | Promise<APIResponse<boolean>> |
|
|||
|
|
|
|||
|
|
#### 3.2.3 使用示例
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 存储数据
|
|||
|
|
await SystemSDK.storage.set('userSettings', { theme: 'dark', lang: 'zh' })
|
|||
|
|
|
|||
|
|
// 获取数据
|
|||
|
|
const settings = await SystemSDK.storage.get('userSettings')
|
|||
|
|
|
|||
|
|
// 监听存储变化
|
|||
|
|
SystemSDK.storage.on('onChange', (key, newValue, oldValue) => {
|
|||
|
|
console.log(`存储变更: ${key} 从 ${oldValue} 变为 ${newValue}`)
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 网络模块(NetworkSDK)
|
|||
|
|
|
|||
|
|
#### 3.3.1 功能概述
|
|||
|
|
|
|||
|
|
提供网络请求能力,支持HTTP请求、文件上传下载等操作。
|
|||
|
|
|
|||
|
|
#### 3.3.2 接口定义
|
|||
|
|
|
|||
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|||
|
|
| ----------------------- | ------------ | ----------------------------------------- | ------------------------------------- |
|
|||
|
|
| request(url, config) | 发送HTTP请求 | url: string, config: NetworkRequestConfig | Promise<APIResponse<NetworkResponse>> |
|
|||
|
|
| get(url, config) | GET请求 | url: string, config: object | Promise<APIResponse<NetworkResponse>> |
|
|||
|
|
| post(url, data, config) | POST请求 | url: string, data: any, config: object | Promise<APIResponse<NetworkResponse>> |
|
|||
|
|
| upload(url, file) | 上传文件 | url: string, file: File/Blob | Promise<APIResponse<NetworkResponse>> |
|
|||
|
|
| download(url, filename) | 下载文件 | url: string, filename: string | Promise<APIResponse<Blob>> |
|
|||
|
|
|
|||
|
|
#### 3.3.3 使用示例
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 发送GET请求
|
|||
|
|
const response = await SystemSDK.network.get('https://api.example.com/users')
|
|||
|
|
|
|||
|
|
// 发送POST请求
|
|||
|
|
const result = await SystemSDK.network.post('https://api.example.com/users', {
|
|||
|
|
name: '张三',
|
|||
|
|
email: 'zhangsan@example.com',
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 上传文件
|
|||
|
|
const fileInput = document.querySelector('input[type="file"]')
|
|||
|
|
if (fileInput.files.length > 0) {
|
|||
|
|
await SystemSDK.network.upload('https://api.example.com/upload', fileInput.files[0])
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.4 事件通信模块(EventSDK)
|
|||
|
|
|
|||
|
|
#### 3.4.1 功能概述
|
|||
|
|
|
|||
|
|
提供应用间以及应用与系统间的事件通信机制,支持广播、点对点通信等模式。
|
|||
|
|
|
|||
|
|
#### 3.4.2 接口定义
|
|||
|
|
|
|||
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|||
|
|
| ------------------------- | -------------- | ----------------------------------- | ----------------------------- |
|
|||
|
|
| emit(channel, data) | 发送事件消息 | channel: string, data: any | Promise<APIResponse<string>> |
|
|||
|
|
| on(channel, callback) | 订阅事件频道 | channel: string, callback: Function | Promise<APIResponse<string>> |
|
|||
|
|
| off(subscriptionId) | 取消订阅 | subscriptionId: string | Promise<APIResponse<boolean>> |
|
|||
|
|
| broadcast(channel, data) | 广播消息 | channel: string, data: any | Promise<APIResponse<string>> |
|
|||
|
|
| sendTo(targetAppId, data) | 发送点对点消息 | targetAppId: string, data: any | Promise<APIResponse<string>> |
|
|||
|
|
|
|||
|
|
#### 3.4.3 使用示例
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 订阅事件
|
|||
|
|
const subscriptionId = await SystemSDK.events.on('user-login', (message) => {
|
|||
|
|
console.log('用户登录:', message.data)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 发送事件
|
|||
|
|
await SystemSDK.events.emit('user-action', { action: 'click', target: 'button1' })
|
|||
|
|
|
|||
|
|
// 取消订阅
|
|||
|
|
await SystemSDK.events.off(subscriptionId)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.5 UI交互模块(UISDK)
|
|||
|
|
|
|||
|
|
#### 3.5.1 功能概述
|
|||
|
|
|
|||
|
|
提供系统级UI交互能力,如对话框、通知、文件选择器等。
|
|||
|
|
|
|||
|
|
#### 3.5.2 接口定义
|
|||
|
|
|
|||
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|||
|
|
| ------------------------- | -------------- | ----------------------------- | ------------------------------ |
|
|||
|
|
| showDialog(options) | 显示对话框 | options: DialogOptions | Promise<APIResponse<object>> |
|
|||
|
|
| showNotification(options) | 显示通知 | options: NotificationOptions | Promise<APIResponse<string>> |
|
|||
|
|
| showFilePicker(options) | 显示文件选择器 | options: FilePickerOptions | Promise<APIResponse<FileList>> |
|
|||
|
|
| showToast(message, type) | 显示Toast消息 | message: string, type: string | Promise<APIResponse<string>> |
|
|||
|
|
|
|||
|
|
#### 3.5.3 使用示例
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 显示确认对话框
|
|||
|
|
const result = await SystemSDK.ui.showDialog({
|
|||
|
|
title: '确认操作',
|
|||
|
|
message: '确定要删除这个文件吗?',
|
|||
|
|
type: 'confirm',
|
|||
|
|
buttons: ['取消', '确定'],
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (result.data.buttonIndex === 1) {
|
|||
|
|
// 用户点击了确定
|
|||
|
|
console.log('用户确认删除')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示通知
|
|||
|
|
await SystemSDK.ui.showNotification({
|
|||
|
|
title: '操作完成',
|
|||
|
|
body: '文件已成功上传',
|
|||
|
|
icon: '/icons/success.png',
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.6 系统信息模块(SystemSDK)
|
|||
|
|
|
|||
|
|
#### 3.6.1 功能概述
|
|||
|
|
|
|||
|
|
提供系统信息查询和基础系统操作能力。
|
|||
|
|
|
|||
|
|
#### 3.6.2 接口定义
|
|||
|
|
|
|||
|
|
| 方法 | 描述 | 参数 | 返回值 |
|
|||
|
|
| ----------------------------- | ---------------- | ------------------ | -------------------------------------- |
|
|||
|
|
| getSystemInfo() | 获取系统信息 | 无 | Promise<APIResponse<SystemInfo>> |
|
|||
|
|
| getAppInfo() | 获取当前应用信息 | 无 | Promise<APIResponse<AppInfo>> |
|
|||
|
|
| requestPermission(permission) | 请求权限 | permission: string | Promise<APIResponse<PermissionStatus>> |
|
|||
|
|
| getClipboard() | 获取剪贴板内容 | 无 | Promise<APIResponse<string>> |
|
|||
|
|
| setClipboard(text) | 设置剪贴板内容 | text: string | Promise<APIResponse<boolean>> |
|
|||
|
|
| openExternal(url) | 打开外部链接 | url: string | Promise<APIResponse<boolean>> |
|
|||
|
|
|
|||
|
|
## 4. 通信机制设计
|
|||
|
|
|
|||
|
|
### 4.1 消息协议
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant A as 子应用SDK
|
|||
|
|
participant B as 主应用沙箱引擎
|
|||
|
|
participant C as 系统服务
|
|||
|
|
|
|||
|
|
A->>B: postMessage(sdk:call, method, data)
|
|||
|
|
B->>C: 调用相应系统服务
|
|||
|
|
C-->>B: 返回处理结果
|
|||
|
|
B-->>A: postMessage(system:response, data)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 消息格式
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// SDK调用消息格式
|
|||
|
|
{
|
|||
|
|
type: 'sdk:call',
|
|||
|
|
requestId: string, // 唯一请求ID
|
|||
|
|
method: string, // 调用方法路径,如 "window.setTitle"
|
|||
|
|
data: any, // 传递的数据
|
|||
|
|
appId: string // 应用ID
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 系统响应消息格式
|
|||
|
|
{
|
|||
|
|
type: 'system:response',
|
|||
|
|
requestId: string, // 对应的请求ID
|
|||
|
|
success: boolean, // 是否成功
|
|||
|
|
data: any, // 成功时的数据
|
|||
|
|
error: string // 失败时的错误信息
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 错误处理机制
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 统一响应格式
|
|||
|
|
interface APIResponse<T> {
|
|||
|
|
success: boolean // 是否成功
|
|||
|
|
data?: T // 成功时的数据
|
|||
|
|
error?: string // 错误信息
|
|||
|
|
code?: number // 错误码
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5. 权限控制设计
|
|||
|
|
|
|||
|
|
### 5.1 权限模型
|
|||
|
|
|
|||
|
|
系统采用基于功能的权限控制模型,应用需要在初始化时声明所需权限。
|
|||
|
|
|
|||
|
|
### 5.2 权限类型
|
|||
|
|
|
|||
|
|
| 权限名称 | 描述 | 敏感级别 |
|
|||
|
|
| ------------------- | -------------- | -------- |
|
|||
|
|
| window.control | 窗口控制权限 | 中 |
|
|||
|
|
| storage.read | 存储读取权限 | 低 |
|
|||
|
|
| storage.write | 存储写入权限 | 中 |
|
|||
|
|
| network.request | 网络请求权限 | 中 |
|
|||
|
|
| event.broadcast | 事件广播权限 | 中 |
|
|||
|
|
| system.clipboard | 剪贴板访问权限 | 高 |
|
|||
|
|
| system.notification | 通知权限 | 低 |
|
|||
|
|
|
|||
|
|
### 5.3 权限申请流程
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TD
|
|||
|
|
A[应用初始化] --> B{权限检查}
|
|||
|
|
B -->|权限已授予| C[正常运行]
|
|||
|
|
B -->|权限未授予| D[请求权限]
|
|||
|
|
D --> E[用户授权]
|
|||
|
|
E -->|允许| C
|
|||
|
|
E -->|拒绝| F[限制功能]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 6. 使用指南
|
|||
|
|
|
|||
|
|
### 6.1 SDK初始化
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 初始化SDK
|
|||
|
|
const result = await SystemSDK.init({
|
|||
|
|
appId: 'com.example.myapp',
|
|||
|
|
appName: '我的应用',
|
|||
|
|
version: '1.0.0',
|
|||
|
|
permissions: ['storage.read', 'storage.write', 'network.request'],
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (result.success) {
|
|||
|
|
console.log('SDK初始化成功')
|
|||
|
|
} else {
|
|||
|
|
console.error('SDK初始化失败:', result.error)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 功能调用示例
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 设置窗口标题
|
|||
|
|
await SystemSDK.window.setTitle('我的应用 - 主界面')
|
|||
|
|
|
|||
|
|
// 存储用户数据
|
|||
|
|
await SystemSDK.storage.set('userData', { name: '张三', age: 25 })
|
|||
|
|
|
|||
|
|
// 发送网络请求
|
|||
|
|
const response = await SystemSDK.network.get('/api/user/profile')
|
|||
|
|
|
|||
|
|
// 显示通知
|
|||
|
|
await SystemSDK.ui.showNotification({
|
|||
|
|
title: '数据加载完成',
|
|||
|
|
body: '用户信息已更新',
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 事件监听示例
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 监听窗口关闭事件
|
|||
|
|
SystemSDK.window.on('close', async () => {
|
|||
|
|
// 保存应用状态
|
|||
|
|
await SystemSDK.storage.set('appState', getCurrentState())
|
|||
|
|
console.log('应用状态已保存')
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// 监听系统主题变化
|
|||
|
|
SystemSDK.system.on('themeChange', (theme) => {
|
|||
|
|
// 更新应用主题
|
|||
|
|
updateAppTheme(theme)
|
|||
|
|
})
|
|||
|
|
```
|