diff --git a/app/web/main.py b/app/web/main.py index a8ab670..788efe9 100644 --- a/app/web/main.py +++ b/app/web/main.py @@ -388,6 +388,24 @@ def api_positions(): tech_service.attach(v["positions"]) except Exception as e: # noqa: BLE001 logger.warning("[持仓] 技术面立场挂不上: %s", e) + # 综合分析三票 (2026-09-15): 每行挂 dims = {fund, tech, timing, fund_fact, tech_phase, nightly}, + # 供持仓表「综合分析」列三枚维度标签用。与扫描同一套装配 (consensus_service.decorate_positions: + # 基本面从逻辑状态映射的买方评析算, 技术面用早上映射, 择时用昨夜定性); 只是显示, 取不到不塌。 + try: + from app.services import consensus_service + _lmap = logic_state_service.state_map() or {} + _crs = {code: (st or {}).get("company_review") for code, st in _lmap.items()} + consensus_service.decorate_positions(v["positions"], company_reviews=_crs) + for r in v["positions"]: + b = r.pop("consensus_blocks", None) or {} + fund, tech, tm = b.get("fund") or {}, b.get("tech") or {}, b.get("timing") or {} + # 技术面优先用 tech_service.attach 挂的那份 (同一映射, 已带相位与理由) + t = r.get("tech") or tech + r["dims"] = {"fund": fund.get("stance"), "fund_fact": fund.get("fact") or fund.get("no_read_why"), + "tech": t.get("stance"), "tech_phase": t.get("phase"), + "timing": tm.get("stance"), "nightly": tm.get("nightly")} + except Exception as e: # noqa: BLE001 + logger.warning("[持仓] 综合分析三票挂不上: %s", e) return {"ok": True, **v, "stock_params": sp} return ok(_view) diff --git a/app/web/static/index.html b/app/web/static/index.html index a4acf98..8f592d0 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -344,8 +344,9 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;} border-bottom:1px dashed rgba(128,128,128,.16);font-size:12.5px;} .sigrow2:last-child{border-bottom:none;} .sigrow2 .t{width:36px;flex:none;font-size:11px;color:var(--muted);} -.sigrow2 .nm{font-weight:620;white-space:nowrap;} -.sigrow2 .cat{color:var(--muted);font-size:11.5px;white-space:nowrap;} +.sigrow2 .nm{font-weight:620;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;} +.sigrow2 .cat{color:var(--muted);font-size:11.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34%;} +.sigrow2 .dim,.sigrow2 .disp{flex:none;white-space:nowrap;} .sigrow2 .sp{flex:1;} .sigrow2.old{opacity:.5;} .sigrow2.clk{cursor:pointer;border-radius:4px;} @@ -449,6 +450,7 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;} .dim.down{background:var(--down-weak);color:var(--down);} .dim.neutral{background:rgba(138,136,130,.14);color:var(--ink-2);} .dim.na{background:transparent;color:var(--muted);border:1px dashed var(--hair);padding:0 6px;} +.dims{display:flex;gap:4px;flex-wrap:wrap;align-items:center;} .prop-sheet{position:fixed;left:0;right:0;bottom:0;z-index:3000;max-height:86vh;overflow:auto; background:var(--surface);border-radius:16px 16px 0 0;box-shadow:0 -12px 40px rgba(17,17,16,.22);} .prop-metric{display:flex;flex-direction:column;gap:7px;margin:8px 0;} @@ -976,15 +978,13 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;}
{{ pct(s.row.cushion_pct) }}
连亏 {{ s.row.neg_cushion_days }} 日
- + @@ -1287,7 +1287,8 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;}
上游的选股计划现在读不到。
当前没有待建仓的候选,都已处理。
+ :title="'查看个股详情' + (dispOf(r.ts_code).label ? ' · ' + dispOf(r.ts_code).label : '') + (dispOf(r.ts_code).why ? ':' + dispOf(r.ts_code).why : '')" + @click="openCodeSignals(r.ts_code)"> 第{{ r.rank }} {{ r.name || nm(r.ts_code) }} {{ r.theme }} @@ -1298,7 +1299,9 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;} 技术面 择时 - {{ dispOf(r.ts_code).label }} + + {{ dispOf(r.ts_code).label }}
受益层级? @@ -1778,16 +1781,14 @@ body.dock-r:not(.r-fold) .side-r .strip{display:none;} class="muted">今天没有读数 - - + + @@ -3152,6 +3153,11 @@ createApp({ // 为什么按合议路由走)。方向按页面口径红涨绿跌; 无读数用中性灰。点开看三票与路由理由。 // 立场 → 颜色类 (2026-09-15, 三处共用): 看多红, 看空绿, 中性灰, 无读数虚框。 const dimCls = (st) => st === '看多' ? 'up' : (st === '看空' ? 'down' : (st === '中性' ? 'neutral' : 'na')); + // 持仓表「综合分析」列: 后端每行挂的 dims (fund/tech/timing 三票与各自一句依据); 没挂就退回技术面那一块。 + const dimsOf = (row) => (row && row.dims) || { tech: (row && row.tech && row.tech.stance) || null, + tech_phase: (row && row.tech && row.tech.phase) || null }; + const NIGHT_CN2 = { BUY: '建议买入', WATCH: '观望', SELL: '建议卖出', AVOID: '回避', DROPPED: '已剔除' }; + const dimTip = (name, st, extra) => name + ' ' + (st || '无读数') + (extra ? ' · ' + (NIGHT_CN2[extra] || extra) : ''); // 基本面行: 立场取硬数字里的 fund_stance (合议六键), 没有就按质地档推; 副文案给质地与估值。 const propFundTag = (p) => { const fs = ((p.hard_numbers || {}).fund_stance || {}).stance, c = cr(p); @@ -4532,7 +4538,7 @@ createApp({ // 2026-09-12 提议卡重构: 来源结论标签 + 详情弹窗 cr, propPlanTag, propPlanSub, propJudgeTag, propCompanyTag, propTechTag, propTechSub, propCon, propConsensusTag, propConsensusSub, - propFundTag, propFundSub, propTimingTag, propTimingSub, propConclusion, dimCls, + propFundTag, propFundSub, propTimingTag, propTimingSub, propConclusion, dimCls, dimsOf, dimTip, propDetailOpen, propDetailKind, propDetailP, propTechFull, propTechErr, PROP_SRC_LABEL, openPropDetail, closePropDetail, pHaltBuy, pResumeBuy, pHaltAll, pResumeAll, pReduce, pIncrease, pLiquidate, pSectorExit,