feat: UI/UX全面优化 — CSS变量体系/a11y无障碍/Admin角色化/骨架屏/打印样式
This commit is contained in:
@@ -193,6 +193,35 @@ def deep_analyze():
|
||||
# 其他情况保持技术面推荐,但更新评分为综合评分
|
||||
else:
|
||||
report['recommend']['rate'] = final_score
|
||||
|
||||
# ---- 追加三项得分汇总到 AI 解说 ----
|
||||
tech_score = comprehensive.get('technical_score', 0)
|
||||
ext_score = comprehensive.get('external_score', 0)
|
||||
fin_score = comprehensive.get('final_score', 0)
|
||||
fin_verdict = comprehensive.get('verdict', '')
|
||||
ext_summary = comprehensive.get('summary', '')
|
||||
|
||||
score_line = (
|
||||
f'综合评分汇总:技术得分{tech_score:.0f}分,'
|
||||
f'外部得分{"+" if ext_score >= 0 else ""}{ext_score}分,'
|
||||
f'综合得分{fin_score}分({fin_verdict})。'
|
||||
)
|
||||
if ext_summary:
|
||||
score_line += f'外部因素:{ext_summary}。'
|
||||
if report.get('ai_summary'):
|
||||
report['ai_summary']['text'] += score_line
|
||||
# 更新 action_tip 以综合得分为准
|
||||
if fin_score >= 80:
|
||||
report['ai_summary']['action_tip'] = '综合评级强烈看多,技术面与外部因素共振看好,可以考虑积极参与。'
|
||||
elif fin_score >= 65:
|
||||
report['ai_summary']['action_tip'] = '综合评级看多,整体偏积极,可以逢低关注。'
|
||||
elif fin_score >= 50:
|
||||
report['ai_summary']['action_tip'] = '综合评级中性偏多,多空均衡,建议观望为主。'
|
||||
elif fin_score >= 35:
|
||||
report['ai_summary']['action_tip'] = '综合评级中性偏空,外部因素拖累,不建议急于买入。'
|
||||
else:
|
||||
report['ai_summary']['action_tip'] = '综合评级看空,外部因素重大利空,建议回避或减仓。'
|
||||
report['ai_summary']['confidence'] = '高' if fin_score >= 70 or fin_score <= 30 else '中'
|
||||
except Exception as e:
|
||||
print(f"综合评分引擎计算失败,使用技术面评分: {e}")
|
||||
|
||||
@@ -655,6 +684,7 @@ def get_scan_results():
|
||||
page = int(request.args.get('page', 1))
|
||||
per_page = int(request.args.get('per_page', 50))
|
||||
sort_by = request.args.get('sort', 'triggered_count')
|
||||
with_scores = request.args.get('with_scores', 'false').lower() == 'true'
|
||||
holding_codes_str = request.args.get('holding_codes', '')
|
||||
holding_set = set(c.strip() for c in holding_codes_str.split(',') if c.strip())
|
||||
recommend_text = (request.args.get('recommend_text') or '').strip()
|
||||
@@ -777,6 +807,29 @@ def get_scan_results():
|
||||
item['holding_note'] = f"若已持仓:{dh}({rh})"
|
||||
results.append(item)
|
||||
|
||||
# ---- 批量计算综合评分,按综合得分重排序 ----
|
||||
if with_scores and results:
|
||||
try:
|
||||
from services.score_engine import compute_comprehensive_score_batch
|
||||
stocks_input = [
|
||||
{'stock_code': r['code'], 'stock_name': r.get('name', ''),
|
||||
'technical_score': r.get('recommend_rate', 50)}
|
||||
for r in results
|
||||
]
|
||||
scores_map = compute_comprehensive_score_batch(stocks_input)
|
||||
for r in results:
|
||||
sc = scores_map.get(r['code'])
|
||||
if sc:
|
||||
r['technical_score'] = sc['technical_score']
|
||||
r['external_score'] = sc['external_score']
|
||||
r['final_score'] = sc['final_score']
|
||||
r['verdict'] = sc['verdict']
|
||||
r['recommend_rate'] = sc['final_score']
|
||||
# 按综合得分降序重排当前页
|
||||
results.sort(key=lambda x: (-x.get('final_score', 0), -x.get('triggered_count', 0)))
|
||||
except Exception as e:
|
||||
print(f'批量综合评分计算失败: {e}')
|
||||
|
||||
if codes_for_page is not None:
|
||||
if codes_for_page:
|
||||
placeholders = ','.join(['%s'] * len(codes_for_page))
|
||||
@@ -808,6 +861,28 @@ def get_scan_results():
|
||||
by_code[code] = item
|
||||
results = [by_code[c] for c in codes_for_page if c in by_code]
|
||||
|
||||
# ---- 批量计算综合评分(recommend_text 筛选路径)----
|
||||
if with_scores and results and codes_for_page is not None:
|
||||
try:
|
||||
from services.score_engine import compute_comprehensive_score_batch
|
||||
stocks_input = [
|
||||
{'stock_code': r['code'], 'stock_name': r.get('name', ''),
|
||||
'technical_score': r.get('recommend_rate', 50)}
|
||||
for r in results
|
||||
]
|
||||
scores_map = compute_comprehensive_score_batch(stocks_input)
|
||||
for r in results:
|
||||
sc = scores_map.get(r['code'])
|
||||
if sc:
|
||||
r['technical_score'] = sc['technical_score']
|
||||
r['external_score'] = sc['external_score']
|
||||
r['final_score'] = sc['final_score']
|
||||
r['verdict'] = sc['verdict']
|
||||
r['recommend_rate'] = sc['final_score']
|
||||
results.sort(key=lambda x: (-x.get('final_score', 0), -x.get('triggered_count', 0)))
|
||||
except Exception as e:
|
||||
print(f'批量综合评分计算失败(recommend_text路径): {e}')
|
||||
|
||||
cur.execute("""
|
||||
SELECT
|
||||
s.value->>'name' as signal_name,
|
||||
@@ -1276,8 +1351,29 @@ def get_bull_stocks():
|
||||
|
||||
conn.close()
|
||||
|
||||
# 使用统一算法找牛股
|
||||
result = find_bull_stocks(scan_rows, holding_codes)
|
||||
# ---- 批量计算综合评分 ----
|
||||
scores_map = None
|
||||
try:
|
||||
from services.score_engine import compute_comprehensive_score_batch
|
||||
# 先用 compute_recommend 算出技术面基础分
|
||||
stocks_input = []
|
||||
for row in scan_rows:
|
||||
sig_status = row.get('signal_status') or []
|
||||
indicators = row.get('indicators') or {}
|
||||
tc = row.get('triggered_count') or 0
|
||||
is_holding = row.get('code', '') in holding_codes
|
||||
_, _, _, rate = compute_recommend(sig_status, indicators, tc, is_holding)
|
||||
stocks_input.append({
|
||||
'stock_code': row.get('code', ''),
|
||||
'stock_name': row.get('name', ''),
|
||||
'technical_score': rate,
|
||||
})
|
||||
scores_map = compute_comprehensive_score_batch(stocks_input)
|
||||
except Exception as e:
|
||||
print(f'牛股筛选综合评分计算失败: {e}')
|
||||
|
||||
# 使用统一算法找牛股(传入综合评分)
|
||||
result = find_bull_stocks(scan_rows, holding_codes, scores_map=scores_map)
|
||||
|
||||
# 为每只股票附加价格信息
|
||||
for stage_num, stocks in result['stages'].items():
|
||||
|
||||
Reference in New Issue
Block a user