修复TUI侧边栏和登录功能

- 修复登录逻辑判断错误,确保正确显示登录页面

- 修复登录成功后不关闭登录界面的问题

- 修复配置区域只显示标题栏的问题

- 添加TUI服务开关,对齐Web设置页面功能

- 完善后端配置处理,支持enable_web/enable_tui/web_port

- 添加登录界面和管理员区域的CSS样式

- 修复Checkbox导入问题

- 优化管理员权限显示逻辑
This commit is contained in:
JianFeeeee
2026-04-29 08:33:41 +08:00
parent 00fd75a0a6
commit bc999b18f1
4 changed files with 126 additions and 19 deletions

View File

@ -469,10 +469,15 @@ class BackendServer:
base_url = api_config.get("base_url", self._config.get("base_url", "https://api.deepseek.com"))
model = api_config.get("model", self._config.get("model", "deepseek-v4-flash"))
self.update_config(api_key, base_url, model)
# 通用配置字段(如 message_timeout
for key in ["message_timeout"]:
# 通用配置字段(如 message_timeout, enable_web, enable_tui, web_port
for key in ["message_timeout", "enable_web", "enable_tui", "web_port"]:
if key in api_config:
self._config[key] = int(api_config[key])
if key == "web_port":
self._config[key] = int(api_config[key])
elif key in ["enable_web", "enable_tui"]:
self._config[key] = bool(api_config[key])
else:
self._config[key] = int(api_config[key])
limits_keys = [
"persona_update_max",

View File

@ -69,8 +69,9 @@ class GraphMemoryApp(App):
from core.migrate import need_migration, is_migrated
# 检查是否需要登录
migrated = is_migrated()
need_login = migrated or not need_migration()
# 如果已迁移,需要登录验证用户
# 如果需要迁移,显示迁移登录界面
need_login = is_migrated() or need_migration()
if need_login and not self.login_user:
# 显示登录界面
@ -84,6 +85,10 @@ class GraphMemoryApp(App):
"""登录成功后调用"""
self.login_user = username
self.login_user_info = user_info
# 关闭登录界面
self.pop_screen()
# 更新 config section 的 admin 权限
from .widgets.config_section import ConfigSection
try:
@ -295,7 +300,10 @@ class GraphMemoryApp(App):
api_config = {
"api_key": config.api_key,
"base_url": config.base_url,
"model": getattr(config, 'model', 'deepseek-v4-flash')
"model": getattr(config, 'model', 'deepseek-v4-flash'),
"enable_web": getattr(config, 'enable_web', False),
"enable_tui": getattr(config, 'enable_tui', True),
"web_port": getattr(config, 'web_port', 4096),
}
tool_limits = {

View File

@ -61,6 +61,45 @@ ConfigSection Input {
color: $text;
}
ConfigSection Checkbox {
margin: 1 0;
}
/* Admin sections */
#admin-web-login-section,
#admin-web-service-section,
#admin-tui-service-section {
display: block;
}
/* Login Screen */
#login_container,
#migration_container {
width: 60;
height: auto;
padding: 2;
background: $surface;
border: solid $primary;
}
#login_title,
#migration_title {
color: $primary;
text-style: bold;
margin: 0 0 1 0;
}
#migration_subtitle {
color: $text-muted;
margin: 0 0 1 0;
}
#login_message,
#migration_message {
color: $warning;
margin: 1 0 0 0;
}
/* Other Components */
OperationLog {
background: $surface-darken-1;

View File

@ -1,7 +1,7 @@
"""配置区组件"""
from textual.containers import Vertical
from textual.widgets import Static, Input, Button
from textual.widgets import Static, Input, Button, Checkbox
from textual.app import ComposeResult
from textual.message import Message
from ..models.config import AppConfig
@ -15,7 +15,7 @@ class ConfigSection(Vertical):
self.is_tool_limits = is_tool_limits
super().__init__()
def __init__(self, config: AppConfig | None = None, is_admin: bool = True, **kwargs):
def __init__(self, config: AppConfig | None = None, is_admin: bool = False, **kwargs):
super().__init__(**kwargs)
self._config = config or AppConfig()
self._is_admin = is_admin
@ -133,7 +133,6 @@ class ConfigSection(Vertical):
ws_hint.can_focus = False
yield ws_hint
from textual.widgets import Checkbox
yield Checkbox(
"启用 Web 服务",
value=self._config.enable_web,
@ -150,10 +149,30 @@ class ConfigSection(Vertical):
type="integer"
)
# 默认隐藏 admin 区域,等 login 后决定是否显示
self._apply_admin_visibility()
sep4 = Static("", classes="config-sep")
sep4.can_focus = False
yield sep4
# TUI 服务控制 — 仅 admin 可见
with Vertical(id="admin-tui-service-section"):
tui_title = Static("━━ TUI 服务 ━━", classes="config-title")
tui_title.can_focus = False
yield tui_title
tui_hint = Static("控制终端文本界面是否允许连接", classes="config-hint")
tui_hint.can_focus = False
yield tui_hint
yield Checkbox(
"启用 TUI 服务",
value=self._config.enable_tui,
id="enable-tui-checkbox"
)
def on_mount(self) -> None:
# 应用管理员区域的可见性
self._apply_admin_visibility()
try:
api_key = self.query_one("#api-key-input", Input)
model = self.query_one("#model-input", Input)
@ -175,17 +194,30 @@ class ConfigSection(Vertical):
web_user.tab_index = 7
web_pwd.tab_index = 8
from textual.widgets import Checkbox
web_port = self.query_one("#web-port-input", Input)
try:
web_checkbox = self.query_one("#enable-web-checkbox", Checkbox)
except:
pass
web_port.tab_index = 9
except Exception:
pass
def on_input_submitted(self, event: Input.Submitted) -> None:
def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
"""处理复选框状态变化"""
try:
# Web 服务开关
if event.checkbox.id == "enable-web-checkbox":
self._update_config_from_ui()
# 发送配置更新消息
self.post_message(self.ConfigChanged(self._config, is_tool_limits=False))
# TUI 服务开关
elif event.checkbox.id == "enable-tui-checkbox":
self._update_config_from_ui()
# 发送配置更新消息
self.post_message(self.ConfigChanged(self._config, is_tool_limits=False))
except Exception:
pass
def _update_config_from_ui(self) -> None:
"""从UI组件更新配置对象"""
try:
api_key_input = self.query_one("#api-key-input", Input)
model_input = self.query_one("#model-input", Input)
@ -199,9 +231,15 @@ class ConfigSection(Vertical):
web_username = self.query_one("#web-username-input", Input)
web_password = self.query_one("#web-password-input", Input)
from textual.widgets import Checkbox
web_checkbox = self.query_one("#enable-web-checkbox", Checkbox)
web_port_input = self.query_one("#web-port-input", Input)
# TUI checkbox 可能不存在(非管理员)
tui_checkbox = None
try:
tui_checkbox = self.query_one("#enable-tui-checkbox", Checkbox)
except:
pass
self._config = AppConfig(
api_key=api_key_input.value,
@ -215,7 +253,14 @@ class ConfigSection(Vertical):
web_password=web_password.value,
enable_web=web_checkbox.value,
web_port=int(web_port_input.value) if web_port_input.value else 4096,
enable_tui=tui_checkbox.value if tui_checkbox else True,
)
except Exception:
pass
def on_input_submitted(self, event: Input.Submitted) -> None:
try:
self._update_config_from_ui()
# 先发送 API 配置更新is_tool_limits=False
self.post_message(self.ConfigChanged(self._config, is_tool_limits=False))
@ -241,6 +286,11 @@ class ConfigSection(Vertical):
service_section.styles.display = "block" if self._is_admin else "none"
except Exception:
pass
try:
tui_section = self.query_one("#admin-tui-service-section")
tui_section.styles.display = "block" if self._is_admin else "none"
except Exception:
pass
def get_config(self) -> AppConfig:
return self._config
@ -264,11 +314,16 @@ class ConfigSection(Vertical):
self.query_one("#web-username-input", Input).value = config.web_username
self.query_one("#web-password-input", Input).value = config.web_password
from textual.widgets import Checkbox
try:
self.query_one("#enable-web-checkbox", Checkbox).value = config.enable_web
except:
pass
self.query_one("#web-port-input", Input).value = str(config.web_port)
# TUI checkbox
try:
self.query_one("#enable-tui-checkbox", Checkbox).value = config.enable_tui
except:
pass
except Exception:
pass