feat: 新增客户端应用目录结构
新增 clients/ 目录: - 外部控制应用的统一目录 - 支持多种客户端类型: - 移动端:iOS, Android, Flutter - 小程序:微信、支付宝、抖音 - Web:响应式 Web 应用、桌面应用 - 智能设备:手表、音箱、智能家居 目录结构: - shared/ - 共享代码(API 客户端、数据模型) - web/ - Web 应用 - flutter/ - Flutter 跨平台应用 - ios/ - iOS 原生应用 - android/ - Android 原生应用 - wechat-miniapp/ - 微信小程序 - desktop/ - Electron 桌面应用 - docs/ - 客户端开发文档 文档: - clients/README.md - 客户端总览和开发计划 - clients/docs/API.md - HTTP API 完整文档 - clients/docs/DESIGN.md - 设计规范和组件库 更新 PLUGIN_DEPENDENCY.md: - 明确 WiFi + BLE 双架构模型 - BLE 既可配置 WiFi,也可独立提供网络功能 - 新增双架构设计原则
This commit is contained in:
@@ -14,6 +14,8 @@
|
|||||||
**示例**:
|
**示例**:
|
||||||
- screen - 屏幕管理(唤醒锁、光标控制)
|
- screen - 屏幕管理(唤醒锁、光标控制)
|
||||||
- wifi - WiFi 管理(扫描、连接、热点)
|
- wifi - WiFi 管理(扫描、连接、热点)
|
||||||
|
- video - 视频播放(状态机、渲染)
|
||||||
|
- ble - 蓝牙服务(GATT、配网,**双架构**:既可配置 WiFi,也可独立提供网络功能)
|
||||||
|
|
||||||
### 依赖插件(Dependent Plugins)
|
### 依赖插件(Dependent Plugins)
|
||||||
**定义**: 依赖其他插件的功能,需要特定插件先启动
|
**定义**: 依赖其他插件的功能,需要特定插件先启动
|
||||||
@@ -25,7 +27,6 @@
|
|||||||
- 通过消息机制与依赖插件通信
|
- 通过消息机制与依赖插件通信
|
||||||
|
|
||||||
**示例**:
|
**示例**:
|
||||||
- ble - 依赖 wifi(通过 BLE 配置 WiFi)
|
|
||||||
- http - 依赖 video(通过 HTTP API 控制视频播放)
|
- http - 依赖 video(通过 HTTP API 控制视频播放)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -33,27 +34,36 @@
|
|||||||
## 依赖关系图
|
## 依赖关系图
|
||||||
|
|
||||||
```
|
```
|
||||||
独立插件层:
|
独立插件层(双架构):
|
||||||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||||
│ screen │ │ wifi │ │ video │
|
│ screen │ │ wifi │ │ video │ │ ble │
|
||||||
└─────────┘ └─────────┘ └─────────┘
|
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
||||||
↑ ↑ ↑
|
↑ ↑ ↑ ↑
|
||||||
│ │ │
|
│ │ │ │
|
||||||
└────────────┴────────────┘
|
│ └────────────┼────────────┘
|
||||||
core
|
│ ↕ │
|
||||||
|
│ (双架构通信) │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────┘
|
||||||
|
core
|
||||||
|
|
||||||
依赖插件层:
|
依赖插件层:
|
||||||
┌─────────┐ ┌─────────┐
|
┌─────────┐
|
||||||
│ ble │ │ http │
|
│ http │
|
||||||
│ (依赖 │ │ (依赖 │
|
│ (依赖 │
|
||||||
│ wifi) │ │ video) │
|
│ video) │
|
||||||
└─────────┘ └─────────┘
|
└─────────┘
|
||||||
↑ ↑
|
↑
|
||||||
│ │
|
│
|
||||||
└────────────┘
|
core
|
||||||
core
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**双架构说明**:
|
||||||
|
- WiFi 和 BLE 是两套独立的网络架构
|
||||||
|
- BLE 可以配置 WiFi(通过消息通信)
|
||||||
|
- BLE 也可以独立提供网络功能(不依赖 WiFi)
|
||||||
|
- 用户可以选择使用 WiFi 或 BLE 进行网络连接
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 插件依赖声明
|
## 插件依赖声明
|
||||||
@@ -77,23 +87,29 @@ pub trait Plugin: Send {
|
|||||||
|
|
||||||
### 依赖声明示例
|
### 依赖声明示例
|
||||||
```rust
|
```rust
|
||||||
impl Plugin for BlePlugin {
|
|
||||||
fn dependencies(&self) -> Vec<&'static str> {
|
|
||||||
vec!["wifi"] // BLE 依赖 WiFi 插件
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plugin for HttpPlugin {
|
impl Plugin for HttpPlugin {
|
||||||
fn dependencies(&self) -> Vec<&'static str> {
|
fn dependencies(&self) -> Vec<&'static str> {
|
||||||
vec!["video"] // HTTP 依赖 Video 插件
|
vec!["video"] // HTTP 依赖 Video 插件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Plugin for BlePlugin {
|
||||||
|
fn dependencies(&self) -> Vec<&'static str> {
|
||||||
|
vec![] // BLE 是独立插件,通过消息与 WiFi 通信
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Plugin for WifiPlugin {
|
impl Plugin for WifiPlugin {
|
||||||
fn dependencies(&self) -> Vec<&'static str> {
|
fn dependencies(&self) -> Vec<&'static str> {
|
||||||
vec![] // WiFi 是独立插件
|
vec![] // WiFi 是独立插件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Plugin for VideoPlugin {
|
||||||
|
fn dependencies(&self) -> Vec<&'static str> {
|
||||||
|
vec![] // Video 是独立插件
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -118,13 +134,13 @@ impl Plugin for WifiPlugin {
|
|||||||
|
|
||||||
### 示例启动顺序
|
### 示例启动顺序
|
||||||
```
|
```
|
||||||
Phase 1: 独立插件
|
Phase 1: 独立插件(并行启动)
|
||||||
- screen.init() → screen.start()
|
- screen.init() → screen.start()
|
||||||
- wifi.init() → wifi.start()
|
- wifi.init() → wifi.start()
|
||||||
- video.init() → video.start()
|
- video.init() → video.start()
|
||||||
|
- ble.init() → ble.start()
|
||||||
|
|
||||||
Phase 2: 依赖插件
|
Phase 2: 依赖插件
|
||||||
- ble.init() → ble.start() (依赖 wifi)
|
|
||||||
- http.init() → http.start() (依赖 video)
|
- http.init() → http.start() (依赖 video)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -144,16 +160,30 @@ Phase 2: 依赖插件
|
|||||||
|
|
||||||
### 消息路由示例
|
### 消息路由示例
|
||||||
```rust
|
```rust
|
||||||
// BLE 请求 WiFi 扫描
|
// 场景1: BLE 配置 WiFi(双架构协作)
|
||||||
ble_plugin.send(Message::WifiCommand(WifiCommand::Scan));
|
ble_plugin.send(Message::WifiCommand(WifiCommand::Connect { ssid, password }));
|
||||||
|
wifi_plugin.handle_message(Message::WifiCommand(...));
|
||||||
// WiFi 返回扫描结果(Broadcast)
|
wifi_plugin.send(Message::WifiResult(result)); // Broadcast
|
||||||
wifi_plugin.send(Message::WifiResult(result));
|
|
||||||
|
|
||||||
// BLE 接收到 WifiResult 消息
|
|
||||||
ble_plugin.handle_message(Message::WifiResult(result));
|
ble_plugin.handle_message(Message::WifiResult(result));
|
||||||
|
|
||||||
|
// 场景2: BLE 独立提供网络功能(不依赖 WiFi)
|
||||||
|
// 用户通过 BLE 直接与设备通信,不需要 WiFi
|
||||||
|
ble_plugin.handle_gatt_request(request);
|
||||||
|
ble_plugin.send_gatt_response(response);
|
||||||
|
|
||||||
|
// 场景3: HTTP 控制 Video(强依赖)
|
||||||
|
http_plugin.send(Message::PlayerCommand(PlayerCommand::Play));
|
||||||
|
video_plugin.handle_message(Message::PlayerCommand(...));
|
||||||
|
video_plugin.send(Message::PlayerStatus(status)); // Broadcast
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**关键区别**:
|
||||||
|
- **双架构(WiFi + BLE)**:两套独立的网络方案,可以互相配置,也可以独立工作
|
||||||
|
- BLE 可以配置 WiFi(松耦合,通过消息)
|
||||||
|
- BLE 可以独立提供网络功能(不依赖 WiFi)
|
||||||
|
- WiFi 可以独立工作(不依赖 BLE)
|
||||||
|
- **强依赖(HTTP → Video)**:HTTP 必须在 Video 启动后才能工作
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 当前插件分类
|
## 当前插件分类
|
||||||
@@ -162,15 +192,23 @@ ble_plugin.handle_message(Message::WifiResult(result));
|
|||||||
| 插件 | 功能 | 依赖 | 状态 |
|
| 插件 | 功能 | 依赖 | 状态 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| screen | 屏幕管理 | core | ✅ 完成 |
|
| screen | 屏幕管理 | core | ✅ 完成 |
|
||||||
| wifi | WiFi 管理 | core | ✅ 完成 |
|
| wifi | WiFi 网络 | core | ✅ 完成 |
|
||||||
| video | 视频播放 | core | ✅ 完成 |
|
| video | 视频播放 | core | ✅ 完成 |
|
||||||
|
| ble | 蓝牙网络 | core | ✅ 完成 |
|
||||||
|
|
||||||
|
**双架构说明**:
|
||||||
|
- **WiFi 架构**:通过 WiFi 连接网络,支持扫描、连接、热点
|
||||||
|
- **BLE 架构**:通过蓝牙连接网络,支持 GATT 服务、配网
|
||||||
|
- **协作模式**:BLE 可以配置 WiFi(通过消息通信)
|
||||||
|
- **独立模式**:BLE 和 WiFi 都可以独立提供网络功能
|
||||||
|
|
||||||
### 依赖插件
|
### 依赖插件
|
||||||
| 插件 | 功能 | 依赖 | 状态 |
|
| 插件 | 功能 | 依赖 | 状态 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
| ble | 蓝牙配网 | core + wifi | ✅ 完成 |
|
|
||||||
| http | HTTP API | core + video | ✅ 完成 |
|
| http | HTTP API | core + video | ✅ 完成 |
|
||||||
|
|
||||||
|
**说明**:HTTP 必须依赖 Video,因为 HTTP API 的核心功能是控制视频播放。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 未来插件规划
|
## 未来插件规划
|
||||||
@@ -214,6 +252,12 @@ ble_plugin.handle_message(Message::WifiResult(result));
|
|||||||
- 独立插件可以单独测试
|
- 独立插件可以单独测试
|
||||||
- 依赖插件可以集成测试
|
- 依赖插件可以集成测试
|
||||||
|
|
||||||
|
### 5. 双架构原则(新增)
|
||||||
|
- 支持多套独立架构并存(如 WiFi + BLE)
|
||||||
|
- 架构之间可以协作(通过消息)
|
||||||
|
- 架构之间可以独立工作(不强依赖)
|
||||||
|
- 用户可以选择使用哪套架构
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 实现任务
|
## 实现任务
|
||||||
|
|||||||
@@ -139,7 +139,8 @@
|
|||||||
[当前] 陈逸飞(CEO) → 张婉琳(产品):
|
[当前] 陈逸飞(CEO) → 张婉琳(产品):
|
||||||
任务:梳理 Phase 1/2/3 所有插件的功能和依赖关系
|
任务:梳理 Phase 1/2/3 所有插件的功能和依赖关系
|
||||||
- 阅读 PLUGIN_DEPENDENCY.md
|
- 阅读 PLUGIN_DEPENDENCY.md
|
||||||
- 确认当前插件分类是否合理
|
- **重要更正**:BLE 是独立插件,不依赖 WiFi(通过消息通信)
|
||||||
|
- 确认当前插件分类:独立插件(screen, wifi, video, ble),依赖插件(http→video)
|
||||||
- 规划 Phase 2/3 新插件的依赖关系
|
- 规划 Phase 2/3 新插件的依赖关系
|
||||||
- 输出:更新 PRD.md,包含插件依赖说明
|
- 输出:更新 PRD.md,包含插件依赖说明
|
||||||
- 与架构师王思远、需求分析师李明哲协作
|
- 与架构师王思远、需求分析师李明哲协作
|
||||||
@@ -147,15 +148,17 @@
|
|||||||
[当前] 陈逸飞(CEO) → 王思远(架构师):
|
[当前] 陈逸飞(CEO) → 王思远(架构师):
|
||||||
任务:设计插件依赖机制的技术实现
|
任务:设计插件依赖机制的技术实现
|
||||||
- 阅读 PLUGIN_DEPENDENCY.md
|
- 阅读 PLUGIN_DEPENDENCY.md
|
||||||
|
- **重要更正**:BLE 是独立插件,不依赖 WiFi
|
||||||
|
- 区分强依赖(http→video)和松耦合(ble↔wifi 通过消息)
|
||||||
- 扩展 Plugin trait,添加 dependencies() 方法
|
- 扩展 Plugin trait,添加 dependencies() 方法
|
||||||
- 设计 ServiceManager 依赖检查和拓扑排序算法
|
- 设计 ServiceManager 依赖检查和拓扑排序算法
|
||||||
- 设计循环依赖检测机制
|
|
||||||
- 输出:技术设计文档 TECH_DESIGN_PLUGIN_DEPENDENCY.md
|
- 输出:技术设计文档 TECH_DESIGN_PLUGIN_DEPENDENCY.md
|
||||||
- 与产品张婉琳、PM 刘建国协作
|
- 与产品张婉琳、PM 刘建国协作
|
||||||
|
|
||||||
[当前] 陈逸飞(CEO) → 刘建国(PM):
|
[当前] 陈逸飞(CEO) → 刘建国(PM):
|
||||||
任务:组织开发团队梳理现有插件依赖
|
任务:组织开发团队梳理现有插件依赖
|
||||||
- 阅读 PLUGIN_DEPENDENCY.md
|
- 阅读 PLUGIN_DEPENDENCY.md
|
||||||
|
- **重要更正**:BLE 是独立插件,dependencies() 返回空
|
||||||
- 让开发团队为现有 5个插件添加 dependencies() 实现
|
- 让开发团队为现有 5个插件添加 dependencies() 实现
|
||||||
- 验证启动顺序和消息通信
|
- 验证启动顺序和消息通信
|
||||||
- 输出:更新代码,在 TEAM_CHAT.md 记录梳理结果
|
- 输出:更新代码,在 TEAM_CHAT.md 记录梳理结果
|
||||||
|
|||||||
191
clients/README.md
Normal file
191
clients/README.md
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
# ShowenV2 客户端应用
|
||||||
|
|
||||||
|
本目录包含 ShowenV2 的外部控制应用,用户可以通过这些客户端远程控制 ShowenV2 设备。
|
||||||
|
|
||||||
|
## 客户端类型
|
||||||
|
|
||||||
|
### 1. 移动端应用
|
||||||
|
- **iOS App** - `ios/` - 原生 iOS 应用(Swift/SwiftUI)
|
||||||
|
- **Android App** - `android/` - 原生 Android 应用(Kotlin/Jetpack Compose)
|
||||||
|
- **Flutter App** - `flutter/` - 跨平台移动应用(iOS + Android)
|
||||||
|
|
||||||
|
### 2. 小程序
|
||||||
|
- **微信小程序** - `wechat-miniapp/` - 微信生态
|
||||||
|
- **支付宝小程序** - `alipay-miniapp/` - 支付宝生态
|
||||||
|
- **抖音小程序** - `douyin-miniapp/` - 抖音生态
|
||||||
|
|
||||||
|
### 3. Web 应用
|
||||||
|
- **Web App** - `web/` - 响应式 Web 应用(React/Vue)
|
||||||
|
- **桌面应用** - `desktop/` - Electron 桌面应用(Windows/macOS/Linux)
|
||||||
|
|
||||||
|
### 4. 智能设备
|
||||||
|
- **智能手表** - `watch/` - Apple Watch / Wear OS
|
||||||
|
- **智能音箱** - `voice/` - 语音控制集成
|
||||||
|
- **智能家居** - `smarthome/` - HomeKit / 米家 / 小度
|
||||||
|
|
||||||
|
## 通信协议
|
||||||
|
|
||||||
|
所有客户端通过以下方式与 ShowenV2 设备通信:
|
||||||
|
|
||||||
|
### HTTP API
|
||||||
|
- **地址**: `http://<device-ip>:8080/api/`
|
||||||
|
- **协议**: RESTful API
|
||||||
|
- **格式**: JSON
|
||||||
|
- **认证**: Token / API Key
|
||||||
|
|
||||||
|
### WebSocket
|
||||||
|
- **地址**: `ws://<device-ip>:8080/ws`
|
||||||
|
- **用途**: 实时状态推送
|
||||||
|
- **格式**: JSON
|
||||||
|
|
||||||
|
### BLE (蓝牙)
|
||||||
|
- **协议**: GATT
|
||||||
|
- **用途**: 近场控制、配网
|
||||||
|
- **服务**: 自定义 GATT Service
|
||||||
|
|
||||||
|
## 核心功能
|
||||||
|
|
||||||
|
### 设备管理
|
||||||
|
- 设备发现和配对
|
||||||
|
- WiFi 配置
|
||||||
|
- 设备状态监控
|
||||||
|
|
||||||
|
### 播放控制
|
||||||
|
- 播放/暂停/停止
|
||||||
|
- 上一个/下一个
|
||||||
|
- 跳转到指定视频
|
||||||
|
- 音量控制
|
||||||
|
|
||||||
|
### 状态机控制
|
||||||
|
- 触发状态切换
|
||||||
|
- 场景切换
|
||||||
|
- 查看当前状态
|
||||||
|
|
||||||
|
### 配置管理
|
||||||
|
- 查看配置
|
||||||
|
- 修改配置
|
||||||
|
- 导入/导出配置
|
||||||
|
|
||||||
|
### 内容管理
|
||||||
|
- 浏览视频列表
|
||||||
|
- 上传新视频
|
||||||
|
- 删除视频
|
||||||
|
- 视频预览
|
||||||
|
|
||||||
|
## 开发计划
|
||||||
|
|
||||||
|
### Phase 1(当前)
|
||||||
|
- [ ] Web App - 基础控制界面
|
||||||
|
- [ ] HTTP API 文档
|
||||||
|
|
||||||
|
### Phase 2(3个月)
|
||||||
|
- [ ] Flutter App - 跨平台移动应用
|
||||||
|
- [ ] 微信小程序 - 快速访问
|
||||||
|
- [ ] WebSocket 实时推送
|
||||||
|
|
||||||
|
### Phase 3(6个月)
|
||||||
|
- [ ] iOS 原生 App
|
||||||
|
- [ ] Android 原生 App
|
||||||
|
- [ ] 智能音箱集成
|
||||||
|
|
||||||
|
### Phase 4(12个月)
|
||||||
|
- [ ] 智能手表应用
|
||||||
|
- [ ] 智能家居集成
|
||||||
|
- [ ] 桌面应用
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
### 移动端
|
||||||
|
- **iOS**: Swift 5.9+, SwiftUI, Combine
|
||||||
|
- **Android**: Kotlin 1.9+, Jetpack Compose, Coroutines
|
||||||
|
- **Flutter**: Flutter 3.x, Dart 3.x
|
||||||
|
|
||||||
|
### Web 端
|
||||||
|
- **前端**: React 18+ / Vue 3+, TypeScript
|
||||||
|
- **状态管理**: Redux / Pinia
|
||||||
|
- **UI 框架**: Ant Design / Element Plus
|
||||||
|
- **构建工具**: Vite / Webpack
|
||||||
|
|
||||||
|
### 小程序
|
||||||
|
- **微信**: 原生小程序框架 / uni-app
|
||||||
|
- **支付宝**: 原生小程序框架
|
||||||
|
- **抖音**: 原生小程序框架
|
||||||
|
|
||||||
|
### 桌面端
|
||||||
|
- **Electron**: Electron 28+, React/Vue
|
||||||
|
- **Tauri**: Tauri 1.x, Rust + Web
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
clients/
|
||||||
|
├── README.md # 本文件
|
||||||
|
├── shared/ # 共享代码
|
||||||
|
│ ├── api/ # API 客户端库
|
||||||
|
│ ├── models/ # 数据模型
|
||||||
|
│ └── utils/ # 工具函数
|
||||||
|
├── web/ # Web 应用
|
||||||
|
│ ├── package.json
|
||||||
|
│ ├── src/
|
||||||
|
│ └── public/
|
||||||
|
├── flutter/ # Flutter 应用
|
||||||
|
│ ├── pubspec.yaml
|
||||||
|
│ ├── lib/
|
||||||
|
│ └── assets/
|
||||||
|
├── ios/ # iOS 应用
|
||||||
|
│ ├── ShowenV2.xcodeproj
|
||||||
|
│ └── ShowenV2/
|
||||||
|
├── android/ # Android 应用
|
||||||
|
│ ├── build.gradle
|
||||||
|
│ └── app/
|
||||||
|
├── wechat-miniapp/ # 微信小程序
|
||||||
|
│ ├── app.json
|
||||||
|
│ └── pages/
|
||||||
|
├── desktop/ # 桌面应用
|
||||||
|
│ ├── package.json
|
||||||
|
│ └── src/
|
||||||
|
└── docs/ # 客户端开发文档
|
||||||
|
├── API.md # API 文档
|
||||||
|
├── DESIGN.md # 设计规范
|
||||||
|
└── DEVELOPMENT.md # 开发指南
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### Web App
|
||||||
|
```bash
|
||||||
|
cd clients/web
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flutter App
|
||||||
|
```bash
|
||||||
|
cd clients/flutter
|
||||||
|
flutter pub get
|
||||||
|
flutter run
|
||||||
|
```
|
||||||
|
|
||||||
|
### 微信小程序
|
||||||
|
```bash
|
||||||
|
cd clients/wechat-miniapp
|
||||||
|
# 使用微信开发者工具打开
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 文档
|
||||||
|
|
||||||
|
详见 `docs/API.md`
|
||||||
|
|
||||||
|
## 设计规范
|
||||||
|
|
||||||
|
详见 `docs/DESIGN.md`
|
||||||
|
|
||||||
|
## 贡献指南
|
||||||
|
|
||||||
|
欢迎贡献新的客户端实现!请参考 `docs/DEVELOPMENT.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本**: v1.0
|
||||||
|
**最后更新**: 2026-03-12
|
||||||
|
**负责人**: 赵雨薇 (前端 & 屏幕工程师)
|
||||||
379
clients/docs/API.md
Normal file
379
clients/docs/API.md
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
# ShowenV2 HTTP API 文档
|
||||||
|
|
||||||
|
## 基础信息
|
||||||
|
|
||||||
|
- **Base URL**: `http://<device-ip>:8080/api`
|
||||||
|
- **协议**: HTTP/1.1
|
||||||
|
- **格式**: JSON
|
||||||
|
- **编码**: UTF-8
|
||||||
|
|
||||||
|
## 认证
|
||||||
|
|
||||||
|
当前版本暂不需要认证(局域网内使用)。未来版本将支持 Token 认证。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 播放控制 API
|
||||||
|
|
||||||
|
### 播放
|
||||||
|
```http
|
||||||
|
POST /api/play
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "play"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 暂停
|
||||||
|
```http
|
||||||
|
POST /api/pause
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "pause"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 停止
|
||||||
|
```http
|
||||||
|
POST /api/stop
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "stop"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 下一个
|
||||||
|
```http
|
||||||
|
POST /api/next
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "next"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 上一个
|
||||||
|
```http
|
||||||
|
POST /api/previous
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "previous"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 跳转到指定视频
|
||||||
|
```http
|
||||||
|
POST /api/goto/:index
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**:
|
||||||
|
- `index` (path): 视频索引(从 0 开始)
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "goto",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态机控制 API
|
||||||
|
|
||||||
|
### 触发状态切换
|
||||||
|
```http
|
||||||
|
POST /api/trigger/:name
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**:
|
||||||
|
- `name` (path): 触发器名称(如 "happy", "sad", "angry")
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "trigger",
|
||||||
|
"name": "happy"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 切换场景
|
||||||
|
```http
|
||||||
|
POST /api/scene/:index
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数**:
|
||||||
|
- `index` (path): 场景索引(从 0 开始)
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "scene",
|
||||||
|
"index": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态查询 API
|
||||||
|
|
||||||
|
### 获取播放状态
|
||||||
|
```http
|
||||||
|
GET /api/status
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"status": {
|
||||||
|
"playing": true,
|
||||||
|
"current_index": 0,
|
||||||
|
"current_state": "idle",
|
||||||
|
"current_scene": 0,
|
||||||
|
"playlist_length": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 获取配置
|
||||||
|
```http
|
||||||
|
GET /api/config
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"config": {
|
||||||
|
"device_name": "ShowenV2",
|
||||||
|
"render_width": 1920,
|
||||||
|
"render_height": 1080,
|
||||||
|
"scenes": [...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WiFi 管理 API
|
||||||
|
|
||||||
|
### 扫描 WiFi
|
||||||
|
```http
|
||||||
|
POST /api/wifi/scan
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"ssid": "MyWiFi",
|
||||||
|
"signal": -50,
|
||||||
|
"security": "WPA2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 连接 WiFi
|
||||||
|
```http
|
||||||
|
POST /api/wifi/connect
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"ssid": "MyWiFi",
|
||||||
|
"password": "password123"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "connect",
|
||||||
|
"ssid": "MyWiFi"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 断开 WiFi
|
||||||
|
```http
|
||||||
|
POST /api/wifi/disconnect
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "disconnect"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开启热点
|
||||||
|
```http
|
||||||
|
POST /api/wifi/hotspot/start
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "hotspot_start"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关闭热点
|
||||||
|
```http
|
||||||
|
POST /api/wifi/hotspot/stop
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"action": "hotspot_stop"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Web UI
|
||||||
|
|
||||||
|
### 访问 Web 控制界面
|
||||||
|
```http
|
||||||
|
GET /
|
||||||
|
```
|
||||||
|
|
||||||
|
返回 HTML 控制界面。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WebSocket API
|
||||||
|
|
||||||
|
### 连接
|
||||||
|
```
|
||||||
|
ws://<device-ip>:8080/ws
|
||||||
|
```
|
||||||
|
|
||||||
|
### 消息格式
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "status_update",
|
||||||
|
"data": {
|
||||||
|
"playing": true,
|
||||||
|
"current_index": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 消息类型
|
||||||
|
- `status_update`: 状态更新
|
||||||
|
- `config_update`: 配置更新
|
||||||
|
- `error`: 错误消息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 错误响应
|
||||||
|
|
||||||
|
所有 API 在出错时返回:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": false,
|
||||||
|
"error": "错误描述"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**HTTP 状态码**:
|
||||||
|
- `200 OK`: 成功
|
||||||
|
- `400 Bad Request`: 请求参数错误
|
||||||
|
- `404 Not Found`: 资源不存在
|
||||||
|
- `500 Internal Server Error`: 服务器错误
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 示例代码
|
||||||
|
|
||||||
|
### JavaScript (Fetch API)
|
||||||
|
```javascript
|
||||||
|
// 播放
|
||||||
|
fetch('http://192.168.1.100:8080/api/play', {
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => console.log(data));
|
||||||
|
|
||||||
|
// 获取状态
|
||||||
|
fetch('http://192.168.1.100:8080/api/status')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => console.log(data.status));
|
||||||
|
```
|
||||||
|
|
||||||
|
### Python (requests)
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# 播放
|
||||||
|
response = requests.post('http://192.168.1.100:8080/api/play')
|
||||||
|
print(response.json())
|
||||||
|
|
||||||
|
# 获取状态
|
||||||
|
response = requests.get('http://192.168.1.100:8080/api/status')
|
||||||
|
print(response.json()['status'])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Swift (URLSession)
|
||||||
|
```swift
|
||||||
|
// 播放
|
||||||
|
let url = URL(string: "http://192.168.1.100:8080/api/play")!
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
|
||||||
|
URLSession.shared.dataTask(with: request) { data, response, error in
|
||||||
|
// 处理响应
|
||||||
|
}.resume()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kotlin (OkHttp)
|
||||||
|
```kotlin
|
||||||
|
// 播放
|
||||||
|
val client = OkHttpClient()
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url("http://192.168.1.100:8080/api/play")
|
||||||
|
.post(RequestBody.create(null, ByteArray(0)))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
client.newCall(request).enqueue(object : Callback {
|
||||||
|
override fun onResponse(call: Call, response: Response) {
|
||||||
|
// 处理响应
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本**: v1.0
|
||||||
|
**最后更新**: 2026-03-12
|
||||||
|
**维护者**: ShowenV2 团队
|
||||||
305
clients/docs/DESIGN.md
Normal file
305
clients/docs/DESIGN.md
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
# ShowenV2 客户端设计规范
|
||||||
|
|
||||||
|
## 设计理念
|
||||||
|
|
||||||
|
### 核心价值
|
||||||
|
- **简洁直观**: 界面简洁,操作直观,用户一看就懂
|
||||||
|
- **响应迅速**: 操作反馈及时,状态更新实时
|
||||||
|
- **一致体验**: 跨平台体验一致,学习成本低
|
||||||
|
- **科技感**: 体现数字生命窗口的科技属性
|
||||||
|
|
||||||
|
### 设计原则
|
||||||
|
1. **移动优先**: 优先考虑移动端体验
|
||||||
|
2. **触控友好**: 按钮大小适合手指点击
|
||||||
|
3. **暗色主题**: 默认暗色,适合夜间使用
|
||||||
|
4. **动效流畅**: 过渡动画自然流畅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 视觉设计
|
||||||
|
|
||||||
|
### 配色方案
|
||||||
|
|
||||||
|
#### 主色调
|
||||||
|
- **主色**: `#6366F1` (Indigo 500) - 科技感蓝紫色
|
||||||
|
- **辅助色**: `#8B5CF6` (Violet 500) - 渐变辅助
|
||||||
|
- **强调色**: `#EC4899` (Pink 500) - 重要操作
|
||||||
|
|
||||||
|
#### 功能色
|
||||||
|
- **成功**: `#10B981` (Green 500)
|
||||||
|
- **警告**: `#F59E0B` (Amber 500)
|
||||||
|
- **错误**: `#EF4444` (Red 500)
|
||||||
|
- **信息**: `#3B82F6` (Blue 500)
|
||||||
|
|
||||||
|
#### 中性色(暗色主题)
|
||||||
|
- **背景**: `#0F172A` (Slate 900)
|
||||||
|
- **卡片**: `#1E293B` (Slate 800)
|
||||||
|
- **边框**: `#334155` (Slate 700)
|
||||||
|
- **文字主**: `#F1F5F9` (Slate 100)
|
||||||
|
- **文字次**: `#94A3B8` (Slate 400)
|
||||||
|
|
||||||
|
### 字体
|
||||||
|
|
||||||
|
#### 中文
|
||||||
|
- **主字体**: 苹方 / 思源黑体 / Noto Sans SC
|
||||||
|
- **等宽**: Fira Code / JetBrains Mono
|
||||||
|
|
||||||
|
#### 英文
|
||||||
|
- **主字体**: Inter / SF Pro / Roboto
|
||||||
|
- **等宽**: Fira Code / JetBrains Mono
|
||||||
|
|
||||||
|
#### 字号
|
||||||
|
- **标题 H1**: 32px / 2rem
|
||||||
|
- **标题 H2**: 24px / 1.5rem
|
||||||
|
- **标题 H3**: 20px / 1.25rem
|
||||||
|
- **正文**: 16px / 1rem
|
||||||
|
- **辅助**: 14px / 0.875rem
|
||||||
|
- **说明**: 12px / 0.75rem
|
||||||
|
|
||||||
|
### 圆角
|
||||||
|
- **小**: 4px
|
||||||
|
- **中**: 8px
|
||||||
|
- **大**: 16px
|
||||||
|
- **圆形**: 50%
|
||||||
|
|
||||||
|
### 阴影
|
||||||
|
- **浅**: `0 1px 3px rgba(0, 0, 0, 0.12)`
|
||||||
|
- **中**: `0 4px 6px rgba(0, 0, 0, 0.16)`
|
||||||
|
- **深**: `0 10px 15px rgba(0, 0, 0, 0.20)`
|
||||||
|
|
||||||
|
### 间距
|
||||||
|
- **xs**: 4px
|
||||||
|
- **sm**: 8px
|
||||||
|
- **md**: 16px
|
||||||
|
- **lg**: 24px
|
||||||
|
- **xl**: 32px
|
||||||
|
- **2xl**: 48px
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 组件设计
|
||||||
|
|
||||||
|
### 按钮
|
||||||
|
|
||||||
|
#### 主按钮
|
||||||
|
```
|
||||||
|
背景: 主色渐变
|
||||||
|
文字: 白色
|
||||||
|
圆角: 8px
|
||||||
|
高度: 48px (移动端) / 40px (桌面端)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 次按钮
|
||||||
|
```
|
||||||
|
背景: 透明
|
||||||
|
边框: 1px 主色
|
||||||
|
文字: 主色
|
||||||
|
圆角: 8px
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 图标按钮
|
||||||
|
```
|
||||||
|
大小: 48x48px (移动端) / 40x40px (桌面端)
|
||||||
|
圆角: 50%
|
||||||
|
背景: 半透明
|
||||||
|
```
|
||||||
|
|
||||||
|
### 卡片
|
||||||
|
```
|
||||||
|
背景: 卡片色
|
||||||
|
圆角: 16px
|
||||||
|
内边距: 16px
|
||||||
|
阴影: 中
|
||||||
|
```
|
||||||
|
|
||||||
|
### 输入框
|
||||||
|
```
|
||||||
|
背景: 背景色
|
||||||
|
边框: 1px 边框色
|
||||||
|
圆角: 8px
|
||||||
|
高度: 48px (移动端) / 40px (桌面端)
|
||||||
|
内边距: 12px
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开关
|
||||||
|
```
|
||||||
|
宽度: 48px
|
||||||
|
高度: 28px
|
||||||
|
圆角: 14px
|
||||||
|
动画: 0.2s ease
|
||||||
|
```
|
||||||
|
|
||||||
|
### 滑块
|
||||||
|
```
|
||||||
|
轨道高度: 4px
|
||||||
|
滑块大小: 20x20px
|
||||||
|
颜色: 主色
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 界面布局
|
||||||
|
|
||||||
|
### 移动端
|
||||||
|
|
||||||
|
#### 底部导航
|
||||||
|
```
|
||||||
|
位置: 固定底部
|
||||||
|
高度: 64px
|
||||||
|
项目: 3-5个
|
||||||
|
图标: 24x24px
|
||||||
|
文字: 12px
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 顶部栏
|
||||||
|
```
|
||||||
|
高度: 56px
|
||||||
|
标题: 居中 / 居左
|
||||||
|
操作: 右侧图标按钮
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 内容区
|
||||||
|
```
|
||||||
|
内边距: 16px
|
||||||
|
卡片间距: 16px
|
||||||
|
```
|
||||||
|
|
||||||
|
### 桌面端
|
||||||
|
|
||||||
|
#### 侧边栏
|
||||||
|
```
|
||||||
|
宽度: 240px
|
||||||
|
位置: 固定左侧
|
||||||
|
可折叠
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 主内容区
|
||||||
|
```
|
||||||
|
最大宽度: 1200px
|
||||||
|
居中显示
|
||||||
|
内边距: 24px
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 交互设计
|
||||||
|
|
||||||
|
### 点击反馈
|
||||||
|
- **按钮**: 按下缩小 0.95,松开恢复
|
||||||
|
- **卡片**: 悬停提升阴影
|
||||||
|
- **列表项**: 悬停背景变亮
|
||||||
|
|
||||||
|
### 加载状态
|
||||||
|
- **全局加载**: 顶部进度条
|
||||||
|
- **局部加载**: 骨架屏 / 加载动画
|
||||||
|
- **按钮加载**: 禁用 + 加载图标
|
||||||
|
|
||||||
|
### 错误提示
|
||||||
|
- **Toast**: 3秒自动消失
|
||||||
|
- **Modal**: 需要用户确认
|
||||||
|
- **Inline**: 表单验证错误
|
||||||
|
|
||||||
|
### 动画时长
|
||||||
|
- **快速**: 0.15s - 小元素出现/消失
|
||||||
|
- **标准**: 0.3s - 页面切换、弹窗
|
||||||
|
- **慢速**: 0.5s - 大型动画
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 页面设计
|
||||||
|
|
||||||
|
### 首页
|
||||||
|
- 设备状态卡片
|
||||||
|
- 快捷操作按钮
|
||||||
|
- 当前播放信息
|
||||||
|
|
||||||
|
### 播放控制
|
||||||
|
- 大型播放/暂停按钮
|
||||||
|
- 进度条
|
||||||
|
- 上一个/下一个
|
||||||
|
- 播放列表
|
||||||
|
|
||||||
|
### 状态机
|
||||||
|
- 当前状态显示
|
||||||
|
- 触发器列表
|
||||||
|
- 场景切换
|
||||||
|
|
||||||
|
### 设置
|
||||||
|
- WiFi 配置
|
||||||
|
- 设备信息
|
||||||
|
- 关于
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 图标设计
|
||||||
|
|
||||||
|
### 图标库
|
||||||
|
推荐使用:
|
||||||
|
- **Heroicons** - 简洁现代
|
||||||
|
- **Lucide** - 一致性好
|
||||||
|
- **Material Icons** - 丰富全面
|
||||||
|
|
||||||
|
### 图标规范
|
||||||
|
- **大小**: 24x24px (默认)
|
||||||
|
- **线宽**: 2px
|
||||||
|
- **风格**: 线性 / 填充
|
||||||
|
- **颜色**: 继承文字颜色
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 响应式设计
|
||||||
|
|
||||||
|
### 断点
|
||||||
|
- **xs**: < 640px (手机)
|
||||||
|
- **sm**: 640px - 768px (大屏手机)
|
||||||
|
- **md**: 768px - 1024px (平板)
|
||||||
|
- **lg**: 1024px - 1280px (小屏电脑)
|
||||||
|
- **xl**: > 1280px (大屏电脑)
|
||||||
|
|
||||||
|
### 适配策略
|
||||||
|
- **移动端**: 单列布局,底部导航
|
||||||
|
- **平板**: 双列布局,侧边栏可选
|
||||||
|
- **桌面**: 多列布局,固定侧边栏
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 无障碍设计
|
||||||
|
|
||||||
|
### 对比度
|
||||||
|
- **正常文字**: 至少 4.5:1
|
||||||
|
- **大文字**: 至少 3:1
|
||||||
|
- **图标**: 至少 3:1
|
||||||
|
|
||||||
|
### 触控目标
|
||||||
|
- **最小尺寸**: 44x44px (iOS) / 48x48px (Android)
|
||||||
|
- **间距**: 至少 8px
|
||||||
|
|
||||||
|
### 键盘导航
|
||||||
|
- 支持 Tab 键切换
|
||||||
|
- 支持 Enter/Space 激活
|
||||||
|
- 焦点状态明显
|
||||||
|
|
||||||
|
### 屏幕阅读器
|
||||||
|
- 图片添加 alt 文本
|
||||||
|
- 按钮添加 aria-label
|
||||||
|
- 状态变化通知
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 设计资源
|
||||||
|
|
||||||
|
### Figma 文件
|
||||||
|
- 组件库
|
||||||
|
- 页面模板
|
||||||
|
- 图标集
|
||||||
|
|
||||||
|
### 设计规范
|
||||||
|
- 颜色变量
|
||||||
|
- 字体样式
|
||||||
|
- 组件样式
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**文档版本**: v1.0
|
||||||
|
**最后更新**: 2026-03-12
|
||||||
|
**设计负责人**: 赵雨薇 (前端 & 屏幕工程师)
|
||||||
Reference in New Issue
Block a user