feat: redesign workspaces and stabilize screeners

This commit is contained in:
leefer
2026-07-26 13:31:45 +08:00
parent 149c468240
commit 6adeb54458
21 changed files with 18786 additions and 917 deletions
+59 -6
View File
@@ -41,9 +41,14 @@ class FrontendContractTests(unittest.TestCase):
def test_all_primary_views_have_navigation_entries(self):
views = set(re.findall(r'id="([A-Za-z][A-Za-z0-9_-]*View|limitPool)" class="workspace-view', self.html))
internal_views = set(re.findall(
r'<section id="([A-Za-z][A-Za-z0-9_-]*View)" class="workspace-view[^"]*"[^>]*\bdata-internal-view\b',
self.html,
))
navigation = set(re.findall(r'data-view="([A-Za-z][A-Za-z0-9_-]*)"', self.html))
self.assertEqual(views, navigation)
self.assertEqual(len(views), 16)
self.assertEqual(views - internal_views, navigation)
self.assertEqual(len(views - internal_views), 16)
self.assertEqual(internal_views, {"screenerTrackingView"})
def test_market_discovery_views_are_wired_end_to_end(self):
for view_id in ("auctionView", "themeLibraryView", "popularityView"):
@@ -63,19 +68,52 @@ class FrontendContractTests(unittest.TestCase):
themes = self.html.index('data-view="themeLibraryView"')
self.assertLess(rotation, auction)
self.assertLess(auction, themes)
for dataset in ("focus", "onePrice", "watchlist", "all"):
for dataset in ("focus", "watchlist", "all", "onePrice"):
self.assertIn(f'data-auction-dataset="{dataset}"', self.html)
dataset_positions = [self.html.index(f'data-auction-dataset="{dataset}"') for dataset in ("focus", "watchlist", "all", "onePrice")]
self.assertEqual(dataset_positions, sorted(dataset_positions))
for filter_name in ("all", "above", "matched", "below"):
self.assertIn(f'data-auction-filter="{filter_name}"', self.html)
self.assertNotIn('data-auction-filter="strong"', self.html)
self.assertNotIn('data-auction-filter="limit"', self.html)
self.assertIn('id="auctionThemeCarry"', self.html)
self.assertIn('id="auctionAmountTrend"', self.html)
self.assertIn('id="auctionNewsTitle"', self.html)
self.assertNotIn('id="auctionNewsTitle"', self.html)
self.assertIn('id="auctionWorkspaceTitle"', self.html)
self.assertIn('id="auctionExpectationFilterbar"', self.html)
self.assertIn('class="auction-news-entry"', self.html)
self.assertIn('class="disabled-status">暂不可用', self.html)
self.assertIn('id="auctionExpectationControls"', self.html)
self.assertNotIn('id="auctionAboveCount"', self.html)
self.assertNotIn('id="auctionMatchedCount"', self.html)
self.assertNotIn('id="auctionBelowCount"', self.html)
self.assertNotIn('class="auction-news-entry"', self.html)
def test_visual_renovation_keeps_required_product_controls(self):
for order in ("oldest", "latest"):
self.assertIn(f'data-rotation-order="{order}"', self.html)
self.assertIn('id="dragonProfilesButton"', self.html)
self.assertIn('id="sentimentHistoryBody"', self.html)
self.assertIn('id="sentimentPreviousPositive"', self.html)
self.assertIn('id="accountDropdown"', self.html)
self.assertIn('id="settingsButton"', self.html)
def test_screener_uses_progressive_strategy_editor(self):
for step in ("regime", "strategy", "run", "result"):
self.assertIn(f'data-screener-step="{step}"', self.html)
def test_screener_exposes_curated_and_quant_workspaces(self):
for mode in ("smart", "curated", "quant"):
self.assertIn(f'data-screener-mode="{mode}"', self.html)
self.assertIn(f'data-screener-panel="{mode}"', self.html)
for element_id in (
"curatedStrategyList", "curatedRunButton", "quantFilterRows",
"quantScoreRows", "quantRunButton", "quantSaveButton",
):
self.assertIn(f'id="{element_id}"', self.html)
self.assertIn('id="strategyDrawer" class="strategy-drawer"', self.html)
self.assertIn('id="openStrategyDrawerButton"', self.html)
self.assertIn('id="closeStrategyDrawerButton"', self.html)
self.assertIn('id="activeStrategyDescription"', self.html)
self.assertIn('openStrategyDrawer("editor")', self.script)
def test_public_knowledge_editors_are_hidden_for_non_admins(self):
self.assertIn('document.querySelector("#reasonForm").hidden = !isAdmin;', self.script)
@@ -177,6 +215,21 @@ class FrontendContractTests(unittest.TestCase):
self.assertIn('elements.tradeLogDialog.showModal()', self.script)
self.assertIn('renderTradeLog();\n closeTradeLogDialog();', self.script)
def test_review_workspace_exposes_complete_watchlist_and_three_part_journal(self):
for label in (
"今日涨幅", "5日涨幅", "竞价关注(分)", "跟踪备注", "添加自选",
"今日盘面一句话", "今日做对了什么 / 做错了什么", "明日策略",
):
self.assertIn(label, self.html)
for element_id in (
"watchlistDialog", "watchlistSearchInput", "watchlistRemark",
"journalSummary", "journalContent", "journalPlan",
):
self.assertIn(f'id="{element_id}"', self.html)
self.assertIn('summary: document.querySelector("#journalSummary").value', self.script)
self.assertIn('return_5d', self.script)
self.assertIn('attention_score', self.script)
def test_heaven_interpretations_use_one_dialog_and_history_tabs(self):
self.assertIn('id="heavenReadingDialog"', self.html)
self.assertIn('data-heaven-reading-tab="current"', self.html)