feat(web): 任务中心全局 Provider / 设置·布局·路由调整 / 视频解析页适配

- tasks.tsx:顶栏任务中心全局 Provider(SSE 任务进度,供各插件页共享)
- 设置页与 AppLayout / client / router 调整,BF2042 插件页路由注册
- web_hub:dashboard / bot_settings 同步更新
- 视频解析页配合后端(缓存 tab / 任务槽进度)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
sansenhoshiandClaude Code committed 2026-10-13 17:53:27 +08:00
1 parent 6af60a7d55
commit 968b3d1cfe
10 files changed
+804 -9

No files matched your search

+37
View File
@@ -32,6 +32,10 @@ _KEY_ENV: dict[str, str] = {
# LOG_LEVEL 可选项(写入时建议大写)
LOG_LEVEL_OPTIONS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
# 资源发送方式(写入 .env 的 HEXI_MEDIA_MODE;语义见 hexi/core/outbound_media._mode)
MEDIA_MODE_OPTIONS = ["http", "base64", "file"]
_MEDIA_MODE_ENV = "HEXI_MEDIA_MODE"
# 日志清理大小(MB)默认值(未在 .env 配置时)
_LOG_MAX_MB_DEFAULT = 20
@@ -103,6 +107,22 @@ def _current_log_max_mb() -> int:
return _LOG_MAX_MB_DEFAULT
def _current_media_mode() -> str:
"""当前资源发送方式(HEXI_MEDIA_MODE > 旧的两个开关 > 默认 http)。
推断规则必须与 `hexi.core.outbound_media._mode` 一致(那边运行时读
os.environ,这边多读一层 .env 文件,好在手改 .env 未重启时也能显示正确)。
"""
raw = _env_get(_MEDIA_MODE_ENV).strip().lower()
if raw in MEDIA_MODE_OPTIONS:
return raw
if _env_get("HEXI_INLINE_MEDIA").strip().lower() in ("0", "false", "no", "off"):
return "file"
if _env_get("HEXI_INLINE_MEDIA_URL").strip().lower() in ("0", "false", "no", "off"):
return "base64"
return "http"
def current_values() -> dict[str, Any]:
"""返回当前生效值(读取优先级:driver.config > .env)。"""
try:
@@ -129,6 +149,8 @@ def current_values() -> dict[str, Any]:
"log_level_options": LOG_LEVEL_OPTIONS,
"log_max_mb": _current_log_max_mb(),
"log_max_mb_default": _LOG_MAX_MB_DEFAULT,
"media_mode": _current_media_mode(),
"media_mode_options": MEDIA_MODE_OPTIONS,
"source": "config" if cfg is not None else "env",
}
@@ -190,6 +212,14 @@ def save_bot_settings(values: dict[str, Any]) -> dict[str, Any]:
if log_max_mb <= 0:
raise ValueError("日志清理大小必须是正整数(MB)")
# 资源发送方式(http/base64/file,写入 HEXI_MEDIA_MODE)
media_mode: str | None = None
_media_mode_raw = values.get("media_mode")
if _media_mode_raw is not None and str(_media_mode_raw).strip() != "":
media_mode = str(_media_mode_raw).strip().lower()
if media_mode not in MEDIA_MODE_OPTIONS:
raise ValueError(f"资源发送方式必须是 {'/'.join(MEDIA_MODE_OPTIONS)} 之一")
# 1. 写 os.environ(即时可读,进程内 getenv 立刻生效)
os.environ["SUPERUSERS"] = _serialize_list(superusers)
os.environ["NICKNAME"] = _serialize_list(nickname)
@@ -197,6 +227,9 @@ def save_bot_settings(values: dict[str, Any]) -> dict[str, Any]:
os.environ["LOG_LEVEL"] = log_level
if log_max_mb is not None:
os.environ["HEXI_LOG_MAX_MB"] = str(log_max_mb)
if media_mode is not None:
# outbound_media._mode() 每次发送现读 os.environ → 保存即生效,无需重启
os.environ[_MEDIA_MODE_ENV] = media_mode
# 2. 落盘 .env(重启后依然生效)
_set_env_line("SUPERUSERS", _serialize_list(superusers))
@@ -205,6 +238,8 @@ def save_bot_settings(values: dict[str, Any]) -> dict[str, Any]:
_set_env_line("LOG_LEVEL", log_level)
if log_max_mb is not None:
_set_env_line("HEXI_LOG_MAX_MB", str(log_max_mb))
if media_mode is not None:
_set_env_line(_MEDIA_MODE_ENV, media_mode)
# 3. 热应用到 driver.config
applied: list[str] = []
@@ -232,6 +267,8 @@ def save_bot_settings(values: dict[str, Any]) -> dict[str, Any]:
_apply_log_level(log_level)
if log_max_mb is not None:
applied.append("HEXI_LOG_MAX_MB")
if media_mode is not None:
applied.append(_MEDIA_MODE_ENV)
return {
"ok": True,