Skip to content

Commit 652c3dd

Browse files
committed
fix(issue-944): [feature]-部署完以后-webui-ui异常变大-布局异常
1 parent dd89d06 commit 652c3dd

5 files changed

Lines changed: 173 additions & 3 deletions

File tree

docs/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1313
<!-- 每条独立一行追加到本段末尾,无需分类标题,合并时冲突最小 -->
1414
- [修复] **MiniMax-M2.7 模型连接测试支持** — 修复 LLM 通道连接测试在 MiniMax-M2.7 模型下返回 "Empty response" 的问题;增加了 `max_tokens` 上限(8→256)以容纳 MiniMax 思考过程,并添加 `content_blocks` 格式解析逻辑统一处理 MiniMax 响应格式差异。
1515
- [修复] 移除 `HistoryItem``ReportSummary` 响应 Schema 中 `sentiment_score``ge=0/le=100` 约束(fixes #942)——历史库中存储的超范围负值或大于 100 的情绪评分不再触发 Pydantic ValidationError,历史列表与详情接口恢复正常返回。
16+
- [修复] webui_frontend.py 在 static/index.html 存在但 static/assets/ 缺失时发出明确警告,避免用户因 CSS/JS 资源缺失导致页面元素异常变大却无从排查
17+
- [文档] DEPLOY.md 和 deploy-webui-cloud.md 新增"UI 元素异常变大/布局错乱"排查步骤(重建 Docker 镜像或手动执行 npm run build)
1618

1719
- [新功能] 集成 Longbridge OpenAPI 作为美股/港股可选数据源;配置 `LONGBRIDGE_*` 后优先使用长桥获取日线与实时行情,YFinance / AkShare 兜底;未配置时行为与此前一致。长桥联调请使用 `tests/longbridge_live_smoke.py`(手动脚本,不参与 pytest 收集)。
1820
- [文档] 澄清 README(中/英/繁)中长桥「首选 / 兜底 / 未配置不调用」的边界;`docs/README_EN.md` / `docs/README_CHT.md` 顶部导航与完整指南链接改为 `./` 相对路径,避免在文档子目录下解析错误;`LONGBRIDGE_PRINT_QUOTE_PACKAGES` 与代码及 `.env.example` 对齐为未设置时默认关闭。

docs/DEPLOY.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,36 @@ deploy:
299299
memory: 1G
300300
```
301301

302+
### 5. WebUI 打开后 UI 元素异常变大 / 布局错乱
303+
304+
**症状**:能访问 8000 端口,但页面上的文字、按钮、卡片异常放大,没有正常布局。
305+
306+
**根因**:`static/index.html` 存在,但 CSS/JS 资源文件缺失(`static/assets/` 为空或不存在),浏览器无法加载样式与脚本,导致裸 HTML 渲染。
307+
308+
**解决方法**:
309+
310+
- **Docker 部署**:执行以下命令重新构建镜像(确保前端已正确打包进镜像):
311+
```bash
312+
docker-compose -f ./docker/docker-compose.yml down
313+
docker-compose -f ./docker/docker-compose.yml build --no-cache
314+
docker-compose -f ./docker/docker-compose.yml up -d
315+
```
316+
构建完成后刷新浏览器缓存(`Ctrl+Shift+R`)再访问。
317+
318+
- **直接部署(pip + python)**:先构建前端,再启动服务:
319+
```bash
320+
# 安装 Node.js 20+(如尚未安装)
321+
# 构建前端
322+
cd apps/dsa-web
323+
npm ci
324+
npm run build
325+
cd ../..
326+
# 启动服务
327+
python main.py --webui-only
328+
```
329+
330+
**验证**:用浏览器开发者工具(F12 → Network)检查是否有 `/assets/index-*.js` 和 `/assets/index-*.css` 的 404 错误;如有,说明资源缺失,按上述步骤重新构建即可。
331+
302332
---
303333

304334
## 🔄 快速迁移

docs/deploy-webui-cloud.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,34 @@ sudo firewall-cmd --reload
209209
- 直接部署:默认 8000,可通过 `WEBUI_PORT=xxxx` 修改
210210
- Docker:默认 8000,可通过 `API_PORT=xxxx` 修改
211211

212+
### 5. 页面能打开,但 UI 元素异常变大 / 布局错乱
213+
214+
**症状**:浏览器能访问到 8000 端口,页面有内容,但文字、按钮、卡片尺寸异常大,没有正常布局与配色。
215+
216+
**根因**`static/index.html` 存在但 CSS/JS 资源缺失(`static/assets/` 为空或不存在),浏览器加载了 HTML 框架但无法拿到样式与脚本,退化为裸 HTML 渲染。
217+
218+
可先用浏览器开发者工具(F12 → Network 标签页)检查是否有 `/assets/index-*.js``/assets/index-*.css`**404** 错误。若有,按以下方式修复:
219+
220+
**Docker 用户**
221+
222+
```bash
223+
docker-compose -f ./docker/docker-compose.yml down
224+
docker-compose -f ./docker/docker-compose.yml build --no-cache
225+
docker-compose -f ./docker/docker-compose.yml up -d
226+
```
227+
228+
重建完成后,用 `Ctrl+Shift+R` 强制刷新浏览器缓存,再访问页面。
229+
230+
**直接部署用户**:先确保已安装 Node.js 20+,然后手动构建前端:
231+
232+
```bash
233+
cd apps/dsa-web
234+
npm ci
235+
npm run build
236+
cd ../..
237+
python main.py --webui-only
238+
```
239+
212240
---
213241

214242
## 可选:Nginx 反向代理(绑定域名 / 80 端口)

src/webui_frontend.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,43 @@ def _run_frontend_commands(commands: Sequence[Sequence[str]], frontend_dir: Path
124124
def _manual_build_command(frontend_dir: Path) -> str:
125125
return f'cd "{frontend_dir}" && npm install && npm run build'
126126

127+
128+
def _has_static_assets(static_dir: Path) -> bool:
129+
"""检查 static/assets/ 是否存在且包含 CSS/JS 文件。
130+
131+
index.html 存在但 assets/ 为空或缺失时,浏览器无法加载样式与脚本,
132+
会导致页面元素异常放大、布局错乱(纯裸 HTML 渲染)。
133+
"""
134+
assets_dir = static_dir / "assets"
135+
if not assets_dir.is_dir():
136+
return False
137+
try:
138+
return any(
139+
f.suffix in (".js", ".css") and f.is_file()
140+
for f in assets_dir.iterdir()
141+
)
142+
except OSError:
143+
return False
144+
145+
146+
def _warn_if_assets_missing(artifact_index: Path, frontend_dir: Path) -> None:
147+
"""当 index.html 存在但 assets/ 缺失时,发出页面显示异常警告。"""
148+
static_dir = artifact_index.parent
149+
if not _has_static_assets(static_dir):
150+
logger.warning(
151+
"检测到 %s 但 static/assets/ 目录不存在或无 CSS/JS 文件,"
152+
"WebUI 将因缺少样式与脚本而显示异常(元素过大、布局错乱)",
153+
artifact_index,
154+
)
155+
logger.warning(
156+
"请重新构建前端以修复此问题: %s",
157+
_manual_build_command(frontend_dir),
158+
)
159+
logger.warning(
160+
"Docker 用户请执行: docker-compose -f ./docker/docker-compose.yml build --no-cache"
161+
)
162+
163+
127164
def prepare_webui_frontend_assets() -> bool:
128165
"""
129166
Prepare frontend assets for WebUI startup.
@@ -143,6 +180,7 @@ def prepare_webui_frontend_assets() -> bool:
143180
if not auto_build_enabled:
144181
if artifact_index.exists():
145182
logger.info("WEBUI_AUTO_BUILD=false,检测到前端静态产物: %s", artifact_index)
183+
_warn_if_assets_missing(artifact_index, frontend_dir)
146184
return True
147185
logger.warning("未检测到 WebUI 前端静态产物: %s", artifact_index)
148186
logger.warning("当前配置 WEBUI_AUTO_BUILD=false,不会在后端启动时自动编译前端")
@@ -155,6 +193,7 @@ def prepare_webui_frontend_assets() -> bool:
155193

156194
if not needs_build:
157195
logger.info("检测到可直接复用的前端静态产物,跳过运行时自动构建: %s", artifact_index)
196+
_warn_if_assets_missing(artifact_index, frontend_dir)
158197
return True
159198

160199
package_json = frontend_dir / "package.json"

tests/test_webui_frontend.py

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@ def _prepare_fake_repo(tmp_path, monkeypatch):
1212
return repo_root
1313

1414

15+
def _create_full_static(repo_root):
16+
"""Create static/index.html + static/assets/*.js/.css (complete build)."""
17+
static_dir = repo_root / "static"
18+
assets_dir = static_dir / "assets"
19+
assets_dir.mkdir(parents=True)
20+
(static_dir / "index.html").write_text("<!doctype html>", encoding="utf-8")
21+
(assets_dir / "index-abc123.js").write_text("/* js */", encoding="utf-8")
22+
(assets_dir / "index-abc123.css").write_text("/* css */", encoding="utf-8")
23+
return static_dir
24+
25+
1526
def test_prepare_webui_frontend_assets_reuses_prebuilt_static_without_source(tmp_path, monkeypatch, caplog):
1627
repo_root = _prepare_fake_repo(tmp_path, monkeypatch)
17-
static_index = repo_root / "static" / "index.html"
18-
static_index.parent.mkdir(parents=True)
19-
static_index.write_text("<!doctype html>", encoding="utf-8")
28+
_create_full_static(repo_root)
2029

2130
monkeypatch.delenv("WEBUI_AUTO_BUILD", raising=False)
2231
monkeypatch.delenv("WEBUI_FORCE_BUILD", raising=False)
@@ -28,6 +37,7 @@ def test_prepare_webui_frontend_assets_reuses_prebuilt_static_without_source(tmp
2837
assert "检测到可直接复用的前端静态产物" in caplog.text
2938
assert "未找到前端项目,无法自动构建" not in caplog.text
3039
assert "未检测到 npm,无法自动构建前端" not in caplog.text
40+
assert "assets/ 目录不存在或无 CSS/JS 文件" not in caplog.text
3141

3242

3343
def test_prepare_webui_frontend_assets_fails_without_static_or_source(tmp_path, monkeypatch, caplog):
@@ -40,3 +50,64 @@ def test_prepare_webui_frontend_assets_fails_without_static_or_source(tmp_path,
4050
assert webui_frontend.prepare_webui_frontend_assets() is False
4151

4252
assert "未找到前端项目,无法自动构建" in caplog.text
53+
54+
55+
def test_prepare_webui_frontend_assets_warns_when_assets_missing(tmp_path, monkeypatch, caplog):
56+
"""index.html 存在但 static/assets/ 缺失时应发出 WebUI 显示异常警告(Issue #944)。"""
57+
repo_root = _prepare_fake_repo(tmp_path, monkeypatch)
58+
static_index = repo_root / "static" / "index.html"
59+
static_index.parent.mkdir(parents=True)
60+
static_index.write_text("<!doctype html>", encoding="utf-8")
61+
# No assets directory created — simulates incomplete/broken build
62+
63+
monkeypatch.delenv("WEBUI_AUTO_BUILD", raising=False)
64+
monkeypatch.delenv("WEBUI_FORCE_BUILD", raising=False)
65+
monkeypatch.setattr(webui_frontend.shutil, "which", lambda _: None)
66+
67+
with caplog.at_level(logging.WARNING):
68+
result = webui_frontend.prepare_webui_frontend_assets()
69+
70+
assert result is True # function still returns True (index.html present)
71+
assert "assets/ 目录不存在或无 CSS/JS 文件" in caplog.text
72+
assert "WebUI 将因缺少样式与脚本而显示异常" in caplog.text
73+
74+
75+
def test_prepare_webui_frontend_assets_auto_build_disabled_warns_when_assets_missing(tmp_path, monkeypatch, caplog):
76+
"""WEBUI_AUTO_BUILD=false 且 assets 缺失时也应发出警告。"""
77+
repo_root = _prepare_fake_repo(tmp_path, monkeypatch)
78+
static_index = repo_root / "static" / "index.html"
79+
static_index.parent.mkdir(parents=True)
80+
static_index.write_text("<!doctype html>", encoding="utf-8")
81+
# No assets directory — simulates state where only index.html exists
82+
83+
monkeypatch.setenv("WEBUI_AUTO_BUILD", "false")
84+
monkeypatch.delenv("WEBUI_FORCE_BUILD", raising=False)
85+
86+
with caplog.at_level(logging.WARNING):
87+
result = webui_frontend.prepare_webui_frontend_assets()
88+
89+
assert result is True # index.html present, still returns True
90+
assert "assets/ 目录不存在或无 CSS/JS 文件" in caplog.text
91+
92+
93+
def test_has_static_assets_returns_false_for_missing_dir(tmp_path):
94+
assert webui_frontend._has_static_assets(tmp_path / "nonexistent") is False
95+
96+
97+
def test_has_static_assets_returns_false_for_empty_assets(tmp_path):
98+
(tmp_path / "assets").mkdir()
99+
assert webui_frontend._has_static_assets(tmp_path) is False
100+
101+
102+
def test_has_static_assets_returns_true_when_js_present(tmp_path):
103+
assets = tmp_path / "assets"
104+
assets.mkdir()
105+
(assets / "main.js").write_text("", encoding="utf-8")
106+
assert webui_frontend._has_static_assets(tmp_path) is True
107+
108+
109+
def test_has_static_assets_returns_true_when_css_present(tmp_path):
110+
assets = tmp_path / "assets"
111+
assets.mkdir()
112+
(assets / "style.css").write_text("", encoding="utf-8")
113+
assert webui_frontend._has_static_assets(tmp_path) is True

0 commit comments

Comments
 (0)