From 55ef6c565a2704349fdbca984666c230299f6596 Mon Sep 17 00:00:00 2001 From: Alfred Date: Sat, 7 Feb 2026 00:29:44 +0800 Subject: [PATCH 01/13] =?UTF-8?q?feat(webui):=20UI=E4=BC=98=E5=8C=96v21-v2?= =?UTF-8?q?2=20-=20LED=E5=8D=A1=E7=89=87=E6=A0=B7=E5=BC=8F=E4=B8=8E?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LED卡片背景统一为白色,消除分割线 - 效果按钮(solid/breathing/sparkle)改为蓝色btn-service-style样式 - LED开关图标改为灯泡(ri-lightbulb-fill/line),开启绿色关闭红色 - 保存按钮改为蓝色无底色remixicon - 风扇曲线模式删除"当前xx%"小字,只显示大蓝色百分比 --- README.md | 48 ++++----- README_EN.md | 30 +++--- TianshanOS frontend modification.md | 95 ++++++++++++++++++ components/ts_webui/web/css/style.css | 102 +++++++++----------- components/ts_webui/web/fonts/remixicon.css | 7 +- components/ts_webui/web/index.html | 2 +- components/ts_webui/web/js/app.js | 52 +++++----- sdkconfig | 8 +- 8 files changed, 211 insertions(+), 133 deletions(-) create mode 100644 TianshanOS frontend modification.md diff --git a/README.md b/README.md index 9d1d802..13d38c9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TianShanOS +# TianshanOS [English](README_EN.md) | [中文](README.md) @@ -20,7 +20,7 @@ ║ ██║ ██║██║ ██║██║ ╚████║███████║██║ ██║██║ ██║██║ ╚████║ ║ ║ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ║ ║ ║ -║ TianShanOS v0.4.0 ║ +║ TianshanOS ║ ║ ESP32 Rack Management Operating System ║ ║ ║ ╚══════════════════════════════════════════════════════════════════════╝ @@ -28,9 +28,9 @@ --- -## 🚀 项目概述 +## 项目概述 -TianShanOS 是一个**面向配置而非面向代码**的嵌入式操作系统框架,基于 ESP-IDF v5.5+ 开发,用于 NVIDIA Jetson AGX + DFRobot LattePanda Mu 载板的机架管理。 +TianshanOS 是一个**面向配置而非面向代码**的嵌入式操作系统框架,基于 ESP-IDF v5.5+ 开发,用于 NVIDIA Jetson AGX + DFRobot LattePanda Mu 载板的机架管理。 ### 核心特性 @@ -43,7 +43,7 @@ TianShanOS 是一个**面向配置而非面向代码**的嵌入式操作系统 - **跨平台设计** - 支持 ESP32-S3 和 ESP32-P4 - **安全优先** - HTTPS/mTLS、SSH 公钥认证、PKI 证书管理、分级权限 - **统一接口** - CLI 和 WebUI 共享 Core API,行为一致 -- **多语言支持** - 中/英/日/韩/德/法/西/乌克兰 8 种语言界面 +- **多语言支持** - 中/英双语界面 - **CI/CD** - GitHub Actions 自动编译、Release 发布 ### 系统架构 @@ -71,10 +71,10 @@ TianShanOS 是一个**面向配置而非面向代码**的嵌入式操作系统 --- -## 📦 项目结构 +## 项目结构 ``` -TianShanOS/ +TianshanOS/ ├── .github/ # GitHub 配置 │ └── workflows/ # CI/CD 工作流 │ └── build.yml # 自动编译 & Release @@ -108,7 +108,7 @@ TianShanOS/ --- -## 🛠️ 开发环境 +## 开发环境 ### 依赖 - ESP-IDF v5.5.2+ @@ -120,7 +120,7 @@ TianShanOS/ ```bash # 克隆项目 git clone https://github.com/thomas-hiddenpeak/TianshanOS.git -cd TianShanOS +cd TianshanOS # 设置 ESP-IDF 环境 . $HOME/esp/v5.5/esp-idf/export.sh @@ -128,7 +128,7 @@ cd TianShanOS # 设置目标芯片 idf.py set-target esp32s3 -# 配置项目 (TianShanOS 选项在顶层菜单) +# 配置项目 (TianshanOS 选项在顶层菜单) idf.py menuconfig # 编译(带版本号更新) @@ -146,7 +146,7 @@ idf.py -p /dev/ttyACM0 flash monitor esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ 0x0 bootloader.bin \ 0x8000 partition-table.bin \ - 0x10000 TianShanOS.bin + 0x10000 TianshanOS.bin ``` ### VS Code 开发 @@ -157,7 +157,7 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ --- -## 📚 文档 +## 文档 | 文档 | 描述 | |-----|------| @@ -178,10 +178,10 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ --- -## 🎯 当前状态 +## 当前状态 **版本**: 0.4.0 -**阶段**: Phase 38 完成 - WebUI 多语言支持 (8种语言) +**阶段**: Phase 38 完成 - WebUI 多语言支持 ### 已完成功能 @@ -196,7 +196,7 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ | 网络 | WiFi、以太网 W5500、HTTP/HTTPS 服务器 | | 安全 | 会话管理、Token 认证、AES-GCM、RSA/EC、SSH 客户端、PKI 证书管理 | | 驱动 | 风扇控制、电源监控 (ADC/INA3221/PZEM)、AGX/LPMU 电源控制、USB MUX | -| WebUI | REST API 网关、WebSocket 广播、前端仪表盘、认证系统、8语言国际化 | +| WebUI | REST API 网关、WebSocket 广播、前端仪表盘、认证系统、中英文国际化 | | OTA | 双分区升级、版本检测、完整性校验、自动回滚 | | 自动化引擎 | 触发器-条件-动作系统、SSH 远程执行、正则解析、变量系统、电压保护集成 | | CI/CD | GitHub Actions 自动编译、Tag 触发 Release 发布 | @@ -234,30 +234,24 @@ esptool.py --chip esp32s3 -p /dev/ttyACM0 write_flash \ --- -## 🌐 多语言支持 +## 多语言支持 -WebUI 支持 8 种语言,根据浏览器设置自动检测: +WebUI 支持中英文界面,根据浏览器设置自动检测: | 语言 | 代码 | |------|------| -| 🇨🇳 简体中文 | zh-CN | -| 🇺🇸 English | en-US | -| 🇯🇵 日本語 | ja-JP | -| 🇰🇷 한국어 | ko-KR | -| 🇩🇪 Deutsch | de-DE | -| 🇫🇷 Français | fr-FR | -| 🇪🇸 Español | es-ES | -| 🇺🇦 Українська | uk-UA | +| 简体中文 | zh-CN | +| English | en-US | --- -## 👥 贡献者 +## 贡献者 - Thomas (项目负责人) - massif-01 --- -## 📄 许可证 +## 许可证 本项目采用 GPL-3.0 许可证,详见 [LICENSE](LICENSE) 文件。 diff --git a/README_EN.md b/README_EN.md index fb9bc2e..bcda0da 100644 --- a/README_EN.md +++ b/README_EN.md @@ -1,10 +1,10 @@ -# TianShanOS +# TianshanOS [English](README_EN.md) | [中文](README.md) -> TianShan Operating System - ESP32 Rack Management Operating System +> Tianshan Operating System - ESP32 Rack Management Operating System > -> TianShan controls both the northern and southern basins — northward to AGX for AI computing power, southward to LPMU for general computing and storage services +> Tianshan controls both the northern and southern basins — northward to AGX for AI computing power, southward to LPMU for general computing and storage services ``` ╔══════════════════════════════════════════════════════════════════════╗ @@ -16,7 +16,7 @@ ║ ██║ ██║██║ ██║██║ ╚████║███████║██║ ██║██║ ██║██║ ╚████║ ║ ║ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ║ ║ ║ -║ TianShanOS v0.3.0 ║ +║ TianshanOS ║ ║ ESP32 Rack Management Operating System ║ ║ ║ ╚══════════════════════════════════════════════════════════════════════╝ @@ -24,9 +24,9 @@ --- -## 🚀 Project Overview +## Project Overview -TianShanOS is a **configuration-oriented rather than code-oriented** embedded operating system framework, developed based on ESP-IDF v5.5+, designed for rack management of NVIDIA Jetson AGX + DFRobot LattePanda Mu carrier boards. +TianshanOS is a **configuration-oriented rather than code-oriented** embedded operating system framework, developed based on ESP-IDF v5.5+, designed for rack management of NVIDIA Jetson AGX + DFRobot LattePanda Mu carrier boards. ### Core Features @@ -38,7 +38,7 @@ TianShanOS is a **configuration-oriented rather than code-oriented** embedded op - **Cross-Platform Design** - Supports ESP32-S3 and ESP32-P4 - **Security First** - HTTPS/mTLS, SSH public key authentication, PKI certificate management, tiered permissions - **Unified Interface** - CLI and WebUI share Core API with consistent behavior -- **Multi-Language Support** - Chinese, English, Japanese, and Korean interface support +- **Multi-Language Support** - Chinese and English interface support ### System Architecture @@ -66,10 +66,10 @@ TianShanOS is a **configuration-oriented rather than code-oriented** embedded op --- -## 📦 Project Structure +## Project Structure ``` -TianShanOS/ +TianshanOS/ ├── components/ # ESP-IDF Components (18 total) │ ├── ts_core/ # Core Framework (config/event/service/log) │ ├── ts_hal/ # Hardware Abstraction Layer (GPIO/PWM/I2C/SPI/UART/ADC) @@ -97,7 +97,7 @@ TianShanOS/ --- -## 🛠️ Development Environment +## Development Environment ### Dependencies - ESP-IDF v5.5.2+ @@ -109,7 +109,7 @@ TianShanOS/ ```bash # Clone the repository git clone https://github.com/thomas-hiddenpeak/TianshanOS.git -cd TianShanOS +cd TianshanOS # Set up ESP-IDF environment . $HOME/esp/v5.5/esp-idf/export.sh @@ -117,7 +117,7 @@ cd TianShanOS # Set target chip idf.py set-target esp32s3 -# Configure project (TianShanOS options are in the top-level menu) +# Configure project (TianshanOS options are in the top-level menu) idf.py menuconfig # Build @@ -135,7 +135,7 @@ For detailed instructions, please refer to the [Quick Start Guide](docs/QUICK_ST --- -## 📚 Documentation +## Documentation | Document | Description | |----------|-------------| @@ -156,7 +156,7 @@ For detailed instructions, please refer to the [Quick Start Guide](docs/QUICK_ST --- -## 🎯 Current Status +## Current Status **Version**: 0.3.0 **Phase**: Phase 20 Complete - Automation Engine, SSH Remote Execution, Variable System @@ -198,7 +198,7 @@ See [Development Progress](docs/DEVELOPMENT_PROGRESS.md) for detailed status. --- -## 👥 Contributors +## Contributors - Thomas (Project Lead) - massif-01 diff --git a/TianshanOS frontend modification.md b/TianshanOS frontend modification.md new file mode 100644 index 0000000..46e7855 --- /dev/null +++ b/TianshanOS frontend modification.md @@ -0,0 +1,95 @@ +# TianshanOS Frontend Modification + +> 精简版:配色规范 + 致命错误 + 编译方法 + 修改历史 + +--- + +## 一、修改原则 + +1. **绝对不改变任何元素的位置和布局** +2. **绝对不删除任何功能按钮或函数** +3. **每次修改代码前必须说「喵喵喵~」** +4. **每次修改后必须更新本文档** + +--- + +## 二、UI 配色规范 + +| 类型 | 背景色 | 文字色 | 边框色 | 用途 | +|-----|--------|--------|--------|------| +| `btn-service-style` | `#f0f8ff` | `#007bff` | `#d0e8ff` | OTA、登出、组件管理 | +| `btn-danger` | `#ffebee` | `#c62828` | `#ef9a9a` | 删除、已关闭 | +| `btn-success` | `#e8f5e9` | `#2e7d32` | `#a5d6a7` | 运行中、添加 | +| `btn-warning` | `#fff8e1` | `#f57c00` | `#ffd54f` | 测试、检测中 | +| 灰色小按钮 | - | `#666` | - | 服务、USB、同步等 | +| 背景色 | `#f5f6fa` | - | - | 曲线点、预览图 | + +--- + +## 三、致命错误经历 + +### 错误 1: 删除功能函数 +修改 emoji 时意外删除 `onclick` 或 JS 函数,导致按钮失效。 +**教训**:只动 HTML 文本,不删逻辑代码。 + +### 错误 2: RemixIcon 未定义 +使用未在 `remixicon.css` 定义的图标类,显示为方框。 +**教训**:先定义 `.ri-xxx:before { content: "\xxxx"; }` 再使用。 + +### 错误 3: www.bin 未更新 +WebUI 修改后直接 `idf.py build`,www.bin 不会重新打包。 +**教训**:必须 `rm build/www.bin` 后再编译。 + +### 错误 4: RemixIcon Unicode 错误 +猜测 Unicode 值导致图标显示错误。 +**教训**:从 `/Users/massif/RemixIcon/fonts/remixicon.css` 查找正确值。 + +### 错误 5: CSS 类名始终存在导致样式残留 +```javascript +// 错误:manual 类始终存在,切换模式后边框残留 + + diff --git a/components/ts_webui/web/js/app.js b/components/ts_webui/web/js/app.js index 501692a..68a0d7c 100644 --- a/components/ts_webui/web/js/app.js +++ b/components/ts_webui/web/js/app.js @@ -534,7 +534,7 @@ async function loadSystemPage() {

资源监控

@@ -996,11 +996,11 @@ function updateAgxPowerButton() { if (!btn) return; if (agxPowerState) { - btn.innerHTML = '🟢 AGX 运行中'; + btn.innerHTML = ' AGX 运行中'; btn.className = 'btn btn-sm btn-success'; btn.title = '点击关闭 AGX 电源'; } else { - btn.innerHTML = '🔴 AGX 已关闭'; + btn.innerHTML = ' AGX 已关闭'; btn.className = 'btn btn-sm btn-danger'; btn.title = '点击开启 AGX 电源'; } @@ -1173,12 +1173,12 @@ function updateLpmuPowerButton(remainingSec = 0) { switch (lpmuState) { case 'online': - btn.innerHTML = '🟢 LPMU 运行中'; + btn.innerHTML = ' LPMU 运行中'; btn.className = 'btn btn-sm btn-success'; btn.title = 'LPMU 在线 (ping 10.10.99.99 可达)\n点击触发电源按钮'; break; case 'offline': - btn.innerHTML = '🔴 LPMU 已关闭'; + btn.innerHTML = ' LPMU 已关闭'; btn.className = 'btn btn-sm btn-danger'; btn.title = 'LPMU 离线 (ping 10.10.99.99 不可达)\n点击触发电源按钮'; break; @@ -1408,8 +1408,8 @@ function updateFanInfo(data) { const modeInfo = { 'off': { label: '关闭', color: '#6b7280', icon: '⏹' }, 'manual': { label: '手动', color: '#f59e0b', icon: '' }, - 'auto': { label: '自动', color: '#10b981', icon: '⚙️' }, - 'curve': { label: '曲线', color: '#3b82f6', icon: '📈' } + 'auto': { label: '自动', color: '#10b981', icon: '' }, + 'curve': { label: '曲线', color: '#3b82f6', icon: '' } }; const currentMode = modeInfo[mode] || modeInfo['auto']; @@ -1427,7 +1427,6 @@ function updateFanInfo(data) {
${displayDuty} % - ${isCurveOrAuto && duty !== displayDuty ? `
当前: ${duty}%
` : ''} ${rpm > 0 ? `
${rpm} RPM
` : ''}
@@ -1435,7 +1434,7 @@ function updateFanInfo(data) {
- @@ -1459,7 +1458,7 @@ function updateFanInfo(data) { ${mode === 'curve' ? ` ` : ''}
`; @@ -1992,8 +1991,8 @@ function drawCurvePreview() { ctx.lineWidth = 2; ctx.stroke(); - // 标签 - ctx.fillStyle = '#fff'; + // 标签(使用坐标轴文字颜色) + ctx.fillStyle = 'rgba(0,0,0,0.7)'; ctx.font = 'bold 10px system-ui'; ctx.textAlign = 'center'; ctx.fillText(`${point.temp}°/${point.duty}%`, x, y - 12); @@ -4649,7 +4648,6 @@ function generateLedDeviceCard(dev) {
-
${icon}
${dev.name} ${description} @@ -4699,13 +4697,12 @@ function generateLedDeviceCard(dev) {
@@ -4804,14 +4801,19 @@ function updateLedCardState(device, isOn, effect = undefined) { // 更新电源按钮 const powerBtn = card.querySelector('.led-power-btn'); if (powerBtn) { + const powerIcon = powerBtn.querySelector('.power-icon'); if (isOn) { powerBtn.classList.add('on'); - powerBtn.querySelector('.power-icon').textContent = '🔆'; - powerBtn.querySelector('.power-text').textContent = '关闭'; + powerBtn.title = '点击关闭'; + if (powerIcon) { + powerIcon.className = 'power-icon ri-lightbulb-fill'; + } } else { powerBtn.classList.remove('on'); - powerBtn.querySelector('.power-icon').textContent = '💡'; - powerBtn.querySelector('.power-text').textContent = '开启'; + powerBtn.title = '点击开启'; + if (powerIcon) { + powerIcon.className = 'power-icon ri-lightbulb-line'; + } } } @@ -14215,8 +14217,8 @@ async function loadOtaPage() {
- - + +
@@ -14263,7 +14265,7 @@ async function loadOtaPage() {
- +
@@ -14274,7 +14276,7 @@ async function loadOtaPage() {
- +
diff --git a/sdkconfig b/sdkconfig index 1efca6a..1df10a4 100644 --- a/sdkconfig +++ b/sdkconfig @@ -370,7 +370,6 @@ CONFIG_SOC_WIFI_HW_TSF=y CONFIG_SOC_WIFI_FTM_SUPPORT=y CONFIG_SOC_WIFI_GCMP_SUPPORT=y CONFIG_SOC_WIFI_WAPI_SUPPORT=y -CONFIG_SOC_WIFI_TXOP_SUPPORT=y CONFIG_SOC_WIFI_CSI_SUPPORT=y CONFIG_SOC_WIFI_MESH_SUPPORT=y CONFIG_SOC_WIFI_SUPPORT_VARIABLE_BEACON_WINDOW=y @@ -1022,7 +1021,6 @@ CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT=2000 # # Hardware Settings # -CONFIG_ESP_HW_SUPPORT_FUNC_IN_IRAM=y # # Chip revision @@ -1083,8 +1081,6 @@ CONFIG_RTC_CLK_SRC_INT_RC=y # CONFIG_RTC_CLK_SRC_EXT_OSC is not set # CONFIG_RTC_CLK_SRC_INT_8MD256 is not set CONFIG_RTC_CLK_CAL_CYCLES=1024 -CONFIG_RTC_CLK_FUNC_IN_IRAM=y -CONFIG_RTC_TIME_FUNC_IN_IRAM=y # end of RTC Clock Config # @@ -1194,9 +1190,9 @@ CONFIG_ESP_PHY_IRAM_OPT=y # # Power Management # -# CONFIG_PM_SLEEP_FUNC_IN_IRAM is not set +CONFIG_PM_SLEEP_FUNC_IN_IRAM=y # CONFIG_PM_ENABLE is not set -# CONFIG_PM_SLP_IRAM_OPT is not set +CONFIG_PM_SLP_IRAM_OPT=y CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP=y # end of Power Management From 811e465d0fc436bfd657afa1bdc7d5b502039b32 Mon Sep 17 00:00:00 2001 From: Alfred Date: Sat, 7 Feb 2026 02:07:08 +0800 Subject: [PATCH 02/13] update: LED color correction UI and gitignore settings - Refactor color correction UI with card-based layout - Fix alignment of header buttons and title - Uniform btn-service-style for export/import buttons - Add TianshanOS frontend modification.md to gitignore to stop tracking it --- .gitignore | 3 + TianshanOS frontend modification.md | 95 --------- components/ts_webui/web/css/style.css | 205 ++++++++++++++++---- components/ts_webui/web/fonts/remixicon.css | 6 +- components/ts_webui/web/index.html | 5 +- components/ts_webui/web/js/app.js | 63 +++--- components/ts_webui/web/js/lang/en-US.js | 1 + components/ts_webui/web/js/lang/zh-CN.js | 1 + 8 files changed, 220 insertions(+), 159 deletions(-) delete mode 100644 TianshanOS frontend modification.md diff --git a/.gitignore b/.gitignore index 4fb5a51..52ea21e 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ tools/pki-server/*.crt *_key secrets/ password*.txt + +# Documentation +TianshanOS frontend modification.md diff --git a/TianshanOS frontend modification.md b/TianshanOS frontend modification.md deleted file mode 100644 index 46e7855..0000000 --- a/TianshanOS frontend modification.md +++ /dev/null @@ -1,95 +0,0 @@ -# TianshanOS Frontend Modification - -> 精简版:配色规范 + 致命错误 + 编译方法 + 修改历史 - ---- - -## 一、修改原则 - -1. **绝对不改变任何元素的位置和布局** -2. **绝对不删除任何功能按钮或函数** -3. **每次修改代码前必须说「喵喵喵~」** -4. **每次修改后必须更新本文档** - ---- - -## 二、UI 配色规范 - -| 类型 | 背景色 | 文字色 | 边框色 | 用途 | -|-----|--------|--------|--------|------| -| `btn-service-style` | `#f0f8ff` | `#007bff` | `#d0e8ff` | OTA、登出、组件管理 | -| `btn-danger` | `#ffebee` | `#c62828` | `#ef9a9a` | 删除、已关闭 | -| `btn-success` | `#e8f5e9` | `#2e7d32` | `#a5d6a7` | 运行中、添加 | -| `btn-warning` | `#fff8e1` | `#f57c00` | `#ffd54f` | 测试、检测中 | -| 灰色小按钮 | - | `#666` | - | 服务、USB、同步等 | -| 背景色 | `#f5f6fa` | - | - | 曲线点、预览图 | - ---- - -## 三、致命错误经历 - -### 错误 1: 删除功能函数 -修改 emoji 时意外删除 `onclick` 或 JS 函数,导致按钮失效。 -**教训**:只动 HTML 文本,不删逻辑代码。 - -### 错误 2: RemixIcon 未定义 -使用未在 `remixicon.css` 定义的图标类,显示为方框。 -**教训**:先定义 `.ri-xxx:before { content: "\xxxx"; }` 再使用。 - -### 错误 3: www.bin 未更新 -WebUI 修改后直接 `idf.py build`,www.bin 不会重新打包。 -**教训**:必须 `rm build/www.bin` 后再编译。 - -### 错误 4: RemixIcon Unicode 错误 -猜测 Unicode 值导致图标显示错误。 -**教训**:从 `/Users/massif/RemixIcon/fonts/remixicon.css` 查找正确值。 - -### 错误 5: CSS 类名始终存在导致样式残留 -```javascript -// 错误:manual 类始终存在,切换模式后边框残留 - +
+ @@ -689,6 +689,7 @@ async function loadSystemPage() {

LED 控制

+
@@ -1184,12 +1185,12 @@ function updateLpmuPowerButton(remainingSec = 0) { break; case 'detecting': const timeText = remainingSec > 0 ? ` (${remainingSec}s)` : ''; - btn.innerHTML = `⏳ 状态获取中${timeText}`; + btn.innerHTML = ` 状态获取中${timeText}`; btn.className = 'btn btn-sm btn-warning'; btn.title = '正在检测 LPMU 状态...\n最多等待 80 秒'; break; default: - btn.innerHTML = '⚠️ LPMU 检测中'; + btn.innerHTML = ' LPMU 检测中'; btn.className = 'btn btn-sm btn-warning'; btn.title = 'LPMU 状态未知\n点击触发电源按钮'; } @@ -2375,9 +2376,11 @@ async function refreshSystemLeds() { // 渲染设备卡片 container.innerHTML = result.data.devices.map(dev => generateLedDeviceCard(dev)).join(''); - // 加载字体列表 + // 加载字体列表 & 显示色彩校正按钮 if (result.data.devices.some(d => d.name === 'matrix' || d.layout === 'matrix')) { loadFontList(); + const ccBtn = document.getElementById('system-led-cc-btn'); + if (ccBtn) ccBtn.style.display = ''; } } else { container.innerHTML = ` @@ -4535,8 +4538,9 @@ async function loadLedPage() {

💡 LED 控制

- - + + +
@@ -4572,9 +4576,11 @@ async function refreshLedPage() { // 渲染设备卡片 container.innerHTML = result.data.devices.map(dev => generateLedDeviceCard(dev)).join(''); - // 加载字体列表 + // 加载字体列表 & 显示色彩校正按钮 if (result.data.devices.some(d => d.name === 'matrix' || d.layout === 'matrix')) { loadFontList(); + const ccBtn = document.getElementById('led-page-cc-btn'); + if (ccBtn) ccBtn.style.display = ''; } } else { container.innerHTML = ` @@ -4628,7 +4634,7 @@ function generateLedDeviceCard(dev) { title="${eff}">${getEffectIcon(eff)}` ).join(''); - // Matrix 设备额外按钮 + // Matrix 设备额外按钮(色彩校正按钮已移至页面头部) const matrixButtons = isMatrix ? ` - ` : ''; return ` @@ -5103,8 +5106,7 @@ function generateLedModalContent(device, type) { } else if (type === 'colorcorrection') { // 色彩校正模态框 return ` -
- ☀️ + ${dev.brightness}
- +
- -
- - - - - - - - +
+
+ + +
+ +
+
+ + + + + + + + + + +
@@ -4694,7 +4706,7 @@ function generateLedDeviceCard(dev) { ${quickEffectsHtml} ${deviceEffects.length > 4 ? `` : ''}
- + ${matrixButtons}
@@ -4703,7 +4715,6 @@ function generateLedDeviceCard(dev) { - ${matrixButtons} @@ -4929,7 +4940,7 @@ function generateLedModalContent(device, type) { const deviceEffects = deviceData?.effects || []; if (type === 'effect') { - // 普通设备的动画模态框 + // 普通设备的动画模态框 - 卡片式布局 const effectsHtml = deviceEffects.length > 0 ? deviceEffects.map(eff => { const isActive = eff === currentAnimation; @@ -4938,27 +4949,47 @@ function generateLedModalContent(device, type) { }).join('') : '暂无可用动画'; + const isOn = ledStates[device] || false; + return ` -