From 6382c8019dc0a245ece06a6fbe5068bd7d2a1006 Mon Sep 17 00:00:00 2001 From: qinglong Date: Sat, 13 Jun 2026 11:34:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20TUI=20=E5=B8=83=E5=B1=80=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20=E2=80=94=20=E7=BB=8F=E5=85=B8=E4=B8=89=E8=A1=8C?= =?UTF-8?q?=EF=BC=9A=E7=8A=B6=E6=80=81=E6=A0=8F=20+=20=E4=B8=BB=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=8C=BA=20+=20=E5=9B=BA=E5=AE=9A=E5=BA=95=E9=83=A8?= =?UTF-8?q?=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 布局改为 grid-rows: auto 1fr 3: - Row 1 (auto): 系统监控 + 插件状态 紧凑状态栏 - Row 2 (1fr): 合并日志/消息为单一可滚动主显示区 - Row 3 (3 lines): 固定高度输入栏,始终可见 同时: - 移除 Header/Footer 节省空间 - show_message 路由到 log_display - 清理未使用的 message_display 分离逻辑 - 移除未使用的 reactive/Horizontal imports Co-Authored-By: Claude --- services/tui_service.py | 150 +++++++++++----------------------------- 1 file changed, 41 insertions(+), 109 deletions(-) diff --git a/services/tui_service.py b/services/tui_service.py index 856d87d..bc772af 100644 --- a/services/tui_service.py +++ b/services/tui_service.py @@ -6,9 +6,8 @@ import sys import io import time from textual.app import App -from textual.containers import Container, ScrollableContainer, Horizontal -from textual.widgets import Static, Input, Header, Footer, LoadingIndicator -from textual.reactive import reactive +from textual.containers import Container, ScrollableContainer +from textual.widgets import Static, Input from textual.suggester import Suggester try: @@ -552,105 +551,46 @@ class TUIFramework(App): def _generate_css(self): - """根据配置动态生成CSS - 增强版""" - try: - tui_config = self.config.get('tui', {}) - layout_config = tui_config.get('layout', {}) - styles_config = tui_config.get('styles', {}) - - # 获取布局配置,使用默认值 - grid_rows = layout_config.get('grid_rows', '7fr 2fr 1fr') - - # 获取样式配置,使用默认值 - log_area_style = styles_config.get('log_area', 'border: solid green; overflow-y: auto;') - message_area_style = styles_config.get('message_area', 'border: solid yellow; overflow-y: auto;') - input_area_style = styles_config.get('input_area', 'border: solid red;') - - css = f""" - Screen {{ - layout: grid; - grid-size: 1 3; - grid-rows: {grid_rows}; - }} - - #log-area {{ - {log_area_style} - overflow-y: auto; - scrollbar-size: 1 1; - }} - - #message-area {{ - {message_area_style} - overflow-y: auto; - scrollbar-size: 1 1; - }} - - #input-area {{ - {input_area_style} - }} - - /* 自定义滚动条样式 */ - ScrollableContainer {{ - scrollbar-color: #666 #222; - scrollbar-color-hover: #888 #333; - overflow-y: auto; - }} - - /* 确保内容正确换行 */ - Static {{ - width: 100%; - content-align: left middle; - overflow-y: auto; - }} - """ - logger.debug(f"生成的TUI CSS:\n{css}") - return css - - except Exception as e: - logger.error(f"生成TUI CSS时出错: {str(e)}", exc_info=True) - # 返回默认CSS作为回退 - return """ + """动态生成 CSS — 经典三行布局:状态栏 + 主内容 + 固定底部输入""" + return """ Screen { layout: grid; grid-size: 1 3; - grid-rows: 7fr 2fr 1fr; + grid-rows: auto 1fr 3; } - - #log-area { - border: solid green; + + #monitor-area { + height: 2; + padding: 0 1; + background: $panel; + color: $text; + } + + #main-area { overflow-y: auto; scrollbar-size: 1 1; + border: solid $primary; } - - #message-area { - border: solid yellow; - overflow-y: auto; - scrollbar-size: 1 1; - } - + #input-area { - border: solid red; + height: 3; + border: solid $secondary; + padding: 0 1; } - - /* 自定义滚动条样式 */ + ScrollableContainer { scrollbar-color: #666 #222; scrollbar-color-hover: #888 #333; - overflow-y: auto; } - - /* 确保内容正确换行 */ + Static { width: 100%; - content-align: left middle; - overflow-y: auto; + content-align: left top; } """ - def compose(self): - """组合界面""" - yield Header() + """组合界面 — 状态栏 / 主显示区(日志+消息) / 底部输入栏""" yield Container( self.system_monitor, self.plugin_panel, @@ -658,23 +598,18 @@ class TUIFramework(App): ) yield ScrollableContainer( self.log_display, - id="log-area" - ) - yield ScrollableContainer( - self.message_display, - id="message-area" + id="main-area", ) self.command_suggester = CommandSuggester(self.command_service) self.command_input = Input( - placeholder="输入指令... Tab 补全", + placeholder="🐱 输入指令... Tab 补全", suggester=self.command_suggester, id="command-input", ) yield Container( self.command_input, - id="input-area" + id="input-area", ) - yield Footer() async def on_mount(self): """挂载完成事件""" @@ -720,16 +655,21 @@ class TUIFramework(App): self.show_message(f"指令处理错误: {str(e)}", "error") def show_message(self, message: str, msg_type: str = "info", persistent: bool = False): - """显示消息""" + """显示消息到主显示区(log_display)""" try: - self.message_display.add_message(message, msg_type, persistent) + prefix = {"info": "ℹ️", "success": "✅", "error": "❌", "warning": "⚠️", + "command": "▶️", "debug": "🔍"}.get(msg_type, "📝") + for line in message.strip().split("\n"): + if line.strip(): + self.log_display.add_log_line(f"{prefix} {line.strip()}") except Exception as e: print(f"❌ 显示TUI消息时出错: {str(e)}") def clear_messages(self, clear_persistent: bool = False): - """清空消息区域""" + """清空主显示区""" try: - self.message_display.clear_messages(clear_persistent) + self.log_display.log_lines.clear() + self.log_display.update("") except Exception as e: print(f"❌ 清空消息时出错: {str(e)}") @@ -853,14 +793,10 @@ class TuiService: result = [] - if target in ["all", "log"]: + if target in ["all", "log", "message"]: log_state = self.tui_app.log_display.toggle_auto_scroll(enabled) - result.append(f"📜 日志自动滚动: {'✅ 启用' if log_state else '❌ 禁用'}") - - if target in ["all", "message"]: - msg_state = self.tui_app.message_display.toggle_auto_scroll(enabled) - result.append(f"💬 消息自动滚动: {'✅ 启用' if msg_state else '❌ 禁用'}") - + result.append(f"📜 自动滚动: {'✅ 启用' if log_state else '❌ 禁用'}") + return "\n".join(result) except Exception as e: @@ -874,14 +810,10 @@ class TuiService: result = [] - if target in ["all", "log"]: + if target in ["all", "log", "message"]: self.tui_app.log_display.scroll_to_bottom() - result.append("📜 日志区域已滚动到底部") - - if target in ["all", "message"]: - self.tui_app.message_display.scroll_to_bottom() - result.append("💬 消息区域已滚动到底部") - + result.append("📜 已滚动到底部") + return "\n".join(result) except Exception as e: