feat(factor): 进度页心跳判活+因子列表默认折叠(用户08-30反馈两项) [vps]
CI/CD / test (push) Successful in 4s
CI/CD / nas-deploy (push) Successful in 11s
CI/CD / nas-verify (push) Successful in 7s

痛点:因子分析分钟级运行,进度条停着看不出进行中还是死掉;240因子罗列乱。
①跨进程心跳链路:analyzer._report_progress 写 {output_dir}/{tid}.progress
(stage/detail/ts;IO故障静默——锦上添花不能伤主流程),埋点=行情加载i/N逐只
+因子特征+逐因子i/M+tears✓+完成;runner._factor_worker 透传 task_id
(默认空串兼容旧调用);GET /task/{id} 合并 _read_factor_progress(factor_
前缀才读,age=距上次活动秒数)。
②Progress.vue终端风重构:心跳区=呼吸灯(绿≤30s/琥珀≤180s静默期/红更久,
prefers-reduced-motion停动画)+「Xs前·detail」+运行时长秒表+步骤%大数字;
因子步骤=行情加载→因子计算→逐因子分析→完成(心跳stage驱动);回测/优化
保持原5步推导+进度条;useTask/TaskStatus 透传 progress。
③FactorPicker默认折叠:groups max-height 128px两行预览+渐隐底边+
「展开全部N个因子▾」按钮,搜索时自动展开。
+5测试(_report_progress写/静默/心跳读roundtrip/非factor/损坏JSON),323绿+build绿
This commit is contained in:
2026-08-30 10:17:19 +08:00
parent 557479b848
commit 8f4f564733
9 changed files with 315 additions and 86 deletions
+27
View File
@@ -130,3 +130,30 @@ def test_universe_pool_and_search(client, token, monkeypatch):
assert r2.status_code == 200 and r2.json() == []
r3 = client.get("/api/v1/factor/universe/search", params={"q": "茅台"}, headers=h)
assert r3.status_code == 200 and len(r3.json()) == 1
# —— 因子进度心跳(_read_factor_progress) ——
def test_read_factor_progress_roundtrip(tmp_path, monkeypatch):
import json, time
from sanguo_api import routes as rt
p = tmp_path / "factor_abc.progress"
p.write_text(json.dumps({"stage": "analyze", "detail": "因子 1/2", "ts": time.time() - 5}),
encoding="utf-8")
monkeypatch.setattr(rt, "_FACTOR_PROGRESS_DIR", str(tmp_path))
d = rt._read_factor_progress("factor_abc")
assert d is not None and d["stage"] == "analyze" and 4 <= d["age"] <= 15
def test_read_factor_progress_bad_input(tmp_path, monkeypatch):
from sanguo_api import routes as rt
# 非 factor 任务恒 None
assert rt._read_factor_progress("cta_123") is None
monkeypatch.setattr(rt, "_FACTOR_PROGRESS_DIR", str(tmp_path))
# 文件不存在 → None
assert rt._read_factor_progress("factor_missing") is None
# 损坏 JSON → None(不影响 status 主链路)
(tmp_path / "factor_bad.progress").write_text("{not json", encoding="utf-8")
assert rt._read_factor_progress("factor_bad") is None