fix: 推荐品种下拉改用缓存 main_code,避免加载卡住。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-25 13:05:26 +08:00
parent fc425c0e9f
commit f05362ea74
2 changed files with 73 additions and 28 deletions
+35 -13
View File
@@ -1,4 +1,35 @@
(function () { (function () {
var recommendedGroupsCache = null;
var recommendedGroupsPromise = null;
function loadRecommendedGroups() {
if (recommendedGroupsCache) {
return Promise.resolve(recommendedGroupsCache);
}
if (recommendedGroupsPromise) {
return recommendedGroupsPromise;
}
recommendedGroupsPromise = fetch('/api/symbols/recommended')
.then(function (r) {
if (!r.ok) {
throw new Error('HTTP ' + r.status);
}
return r.json();
})
.then(function (groups) {
recommendedGroupsCache = Array.isArray(groups) ? groups : [];
return recommendedGroupsCache;
})
.catch(function () {
recommendedGroupsCache = null;
throw new Error('load failed');
})
.finally(function () {
recommendedGroupsPromise = null;
});
return recommendedGroupsPromise;
}
function formatSub(item) { function formatSub(item) {
var sub = '同花顺 ' + item.ths_code + var sub = '同花顺 ' + item.ths_code +
(item.market_code ? ' · ' + item.market_code : '') + (item.market_code ? ' · ' + item.market_code : '') +
@@ -47,7 +78,6 @@
let abortCtrl = null; let abortCtrl = null;
const cache = new Map(); const cache = new Map();
let mainsCache = null; let mainsCache = null;
let mainsLoading = false;
function hideDropdown() { function hideDropdown() {
dropdown.classList.remove('show'); dropdown.classList.remove('show');
@@ -135,16 +165,9 @@
renderGrouped(mainsCache, q); renderGrouped(mainsCache, q);
return; return;
} }
if (mainsLoading) {
dropdown.innerHTML = '<div class="symbol-option">正在加载推荐品种…</div>'; dropdown.innerHTML = '<div class="symbol-option">正在加载推荐品种…</div>';
dropdown.classList.add('show'); dropdown.classList.add('show');
return; loadRecommendedGroups()
}
mainsLoading = true;
dropdown.innerHTML = '<div class="symbol-option">正在加载推荐品种…</div>';
dropdown.classList.add('show');
fetch('/api/symbols/recommended')
.then(function (r) { return r.json(); })
.then(function (groups) { .then(function (groups) {
mainsCache = groups; mainsCache = groups;
if (!groups.length) { if (!groups.length) {
@@ -156,10 +179,9 @@
showMarketMains(filterQ, onEmpty); showMarketMains(filterQ, onEmpty);
}) })
.catch(function () { .catch(function () {
hideDropdown(); dropdown.innerHTML =
}) '<div class="symbol-option">推荐品种加载失败,请刷新页面或输入合约代码搜索</div>';
.finally(function () { dropdown.classList.add('show');
mainsLoading = false;
}); });
} }
+38 -15
View File
@@ -431,15 +431,42 @@ def _product_for_ths(ths: str) -> Optional[dict]:
return _THS_TO_PRODUCT.get(key) or _THS_TO_PRODUCT.get(key.lower()) return _THS_TO_PRODUCT.get(key) or _THS_TO_PRODUCT.get(key.lower())
def _main_for_product(product: dict) -> Optional[dict]: def _item_from_recommend_row(row: dict, product: dict) -> Optional[dict]:
"""由推荐缓存行快速构造下拉项(不在 HTTP 请求中解析主力)。"""
name = row.get("name") or product["name"]
main_code = (row.get("main_code") or "").strip()
max_lots = row.get("max_lots")
if main_code:
codes = ths_to_codes(main_code)
if codes:
ths = codes["ths_code"]
item = {
"name": name,
"ths_code": ths,
"market_code": codes.get("market_code") or "",
"sina_code": codes.get("sina_code") or "",
"exchange": product["exchange"],
"contract": f"主力 {ths}",
"display": f"{name} 主力 {ths}",
"input_label": f"{name} {ths}",
}
if max_lots is not None:
item["max_lots"] = max_lots
return _enrich_item(item)
with _main_index_lock: with _main_index_lock:
index = dict(_main_index) main = _main_index.get(product["sina"])
main = index.get(product["sina"]) if main:
if not main: item = dict(main)
resolved = resolve_main_contract(product) if max_lots is not None:
if resolved: item["max_lots"] = max_lots
main = _enrich_item(resolved) return _enrich_item(item)
return main
item = _stub_main_contract(product)
if max_lots is not None:
item["max_lots"] = max_lots
return item
def list_recommended_symbols_grouped(recommend_rows: list[dict]) -> list[dict]: def list_recommended_symbols_grouped(recommend_rows: list[dict]) -> list[dict]:
@@ -459,14 +486,10 @@ def list_recommended_symbols_grouped(recommend_rows: list[dict]) -> list[dict]:
if not product: if not product:
continue continue
seen.add(ths_key) seen.add(ths_key)
main = _main_for_product(product) item = _item_from_recommend_row(row, product)
if not main: if not item:
continue continue
item = dict(main) buckets[product["exchange"]].append(item)
max_lots = row.get("max_lots")
if max_lots is not None:
item["max_lots"] = max_lots
buckets[product["exchange"]].append(_enrich_item(item))
groups: list[dict] = [] groups: list[dict] = []
for cat in EXCHANGE_ORDER: for cat in EXCHANGE_ORDER: