diff --git a/DEVLOG.md b/DEVLOG.md index a080c80..8c5a94c 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -30,6 +30,54 @@ --- +## 2026-08-18 · 上游信号面板改版:删下线框 + 按重要度分档 + 资金异动 z 可读化 + 待触发条 + +**做了什么** +重排管理页面「上游信号」面板(app/web/static/index.html 单页,纯前端,不动后端)。四件事。 +一,删掉「放量异动」框:该源(volume_capitulation/breakout)6/15 已被资金分布取代, +生产端(intraday_timing orchestrator 方向源清单)不再发它,框永远只显示历史残留键。 +二,卡片按重要度分三档、大小不一:行动级(决策买卖 c-wide、择时入场、风控卖出、多源升级) +有数据才出大卡;判读级(资金异动、QRS、资金分布、资金流强度)中卡两列;参考级(股价异动 +小卡、实况分榜宽卡)。用 12 列网格 + c-wide/c-half/c-third 跨列实现。 +三,资金异动「异动z」换成净额领读 + 强度带:净额折成万/亿带正负号打头,强度按 z_dd 绝对值 +分档(显著 2–3 / 强 3–5 / 极强 ≥5)用小方块条 + 中文标签表达,原始 z 收进悬停提示。 +四,空的「在用」信号收进一条「在用·今日待触发」横条(armed 待命,不再各占空框)——这是 +本次核心:此前四个空框和一个死框摆一起,看不出「活着但安静」和「已下线」的区别,用户误以为 +下线了。逐个追到生产端核实:只有放量异动真下线,多源升级/择时层BUY/风控卖出/资金流强度都是 +在用但罕见或条件触发。「其他」桶只在非空时出现(空=所有源已登记=健康)。 + +**动了哪些文件** +app/web/static/index.html:新增 CSS(sig-tier/sig-grid/c-*/intens/ibar/armed 等);新增 JS +(moneyCn、zBand、zBars、dirUp、SIG 组装、armed 待触发、CARDS_B、tierHasA/B/C 计算属性, +并加入 setup return);替换整个 up-grid 模板为三档 + 待触发条 + 其他桶。旧的 alertGridFixed +等计算属性留着未删(无害,减少改动面)。 + +**部署方式** +factorevaluation 上 `make deploy`(前端资源打进镜像)。纯前端改动,不动后端与取数口径。 +回滚只需还原 index.html 一个文件。 + +**真机判收** +开发机已做无头渲染判收(Playwright 加载真页面 + 造数):三档正确渲染、待触发条正确收纳空信号、 +强度带与万/亿格式生效、放量异动消失、无任何 Vue 编译/运行告警;node 语法检查与括号平衡通过; +全页 Vue 模板编译无错。真机待看:盘中有真数据时各档卡片与截图一致,且级别筛选条仍联动。 + +**还欠着什么** +待触发条目前只标「今日待触发」,未显示「最近一次触发时间」(那需要后端跨日扫历史键,会给每次 +刷新加延迟,暂不做;用户认可先不加)。强度分档三个阈值(2–3/3–5/≥5)可按盘中手感再调。 + +**同日修订(改版二,用户反馈:分档布局太乱、要固定成对)** +把"按重要度分三档 + 卡片宽度随内容变(c-wide/c-third)"改成**固定成对网格**,位置稳定不再随 +数据重排,整体更对称干净。三对(用户指定)各占一行、两两并排等宽等高:① mtf 资金异动 | +mtf 实况分榜(这对通常列表长,单独拉高到 min-height 340,两边等高并排);② 决策系统买卖 | +日QRS对称;③ 资金分布 | 股价异动。这六个常用框**常驻**(空了框内显示"暂无",不再消失/重排)。 +四个稀有或条件触发的信号(风控卖出、多源升级、择时层BUY、资金流强度)归入下方「事件信号」区: +触发了才出卡,没触发的收进一条「在用·今日待触发」;「其他/未登记源」桶也并进这条、非空才显示。 +去掉了三档标题与 c-wide/c-half/c-third 变宽卡,新增 .sig2(成对行)/.sig2.tall/.sig-ev(事件卡); +删掉不再用的 tierHasA/B/C、CARDS_B、armed 计算属性。判收:无头渲染六框全在、事件卡与待触发条 +各自正确、零 Vue 告警。旧的"分档版"未曾部署,改版二是最终形态。 + +--- + ## 2026-08-17 · 清仓择时改造:紧急直通 + 卖出分桶收口 + 自主卖出窗口不作废 **做了什么** diff --git a/app/web/static/index.html b/app/web/static/index.html index 6838f38..1e846a0 100644 --- a/app/web/static/index.html +++ b/app/web/static/index.html @@ -109,6 +109,38 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius: .up-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:16px;} .up-cell{border:1px solid var(--hair);border-radius:11px;padding:12px 14px;background:var(--surface-2);} .up-h{font-size:13px;font-weight:640;color:var(--ink-2);margin-bottom:8px;} +/* 上游信号改版 (2026-08-18): 按重要度分档 + 空的在用信号收进待触发条 */ +.sig-tier{margin-top:16px;} +.sig-tier-h{display:flex;align-items:baseline;gap:8px;margin:0 0 9px;flex-wrap:wrap;} +.sig-tier-h .tt{font-size:10px;font-weight:700;padding:1px 7px;border-radius:5px;letter-spacing:.3px;} +.tt-a{background:var(--stop-weak);color:var(--stop);} .tt-b{background:var(--accent-weak);color:var(--accent);} .tt-c{background:rgba(138,136,130,.14);color:var(--ink-2);} +.sig-tier-h b{font-size:13px;} .sig-tier-h .d{font-size:11px;color:var(--ink-2);} +.sig-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:14px;} +.sig-grid .up-cell{margin:0;} +.c-wide{grid-column:span 8;} .c-half{grid-column:span 6;} .c-third{grid-column:span 4;} +@media(max-width:960px){.c-wide,.c-half,.c-third{grid-column:span 12;}} +.sig-rows{max-height:210px;overflow:auto;} +.sig-row{display:flex;align-items:center;gap:8px;padding:6px 0;border-top:1px solid var(--hair);font-size:13px;} +.sig-row:first-child{border-top:none;} +.sig-nm{font-weight:600;} .sig-sp{flex:1;} +.intens{display:inline-flex;align-items:center;gap:5px;} +.ibar{display:inline-flex;gap:2px;} +.ibar i{width:4px;height:11px;border-radius:1px;background:var(--hair);display:inline-block;} +.ibar i.on{background:var(--ink-2);} +.armed{display:flex;align-items:center;gap:9px;flex-wrap:wrap;border:1px dashed var(--hair);border-radius:10px;padding:9px 13px;background:var(--surface-2);} +.armed .lead{font-size:12px;color:var(--ink-2);font-weight:600;} +.armed .chip{display:inline-flex;align-items:center;gap:6px;font-size:12px;padding:3px 10px;border-radius:14px;background:var(--surface);border:1px solid var(--hair);} +.armed .chip .dot{width:6px;height:6px;border-radius:50%;background:#c9c7c0;} +.armed .chip.dead{text-decoration:line-through;opacity:.55;} +/* 固定成对网格 (2026-08-18 改版二): 三对各占一行, 位置稳定不重排; mtf 一对并排拉高 */ +.sig2{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px;align-items:stretch;} +@media(max-width:880px){.sig2{grid-template-columns:1fr;}} +.sig2 .up-cell{min-height:200px;display:flex;flex-direction:column;margin:0;} +.sig2.tall .up-cell{min-height:340px;} +.sig2 .sig-rows{flex:1;max-height:none;} +.sig-ev{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px;margin-top:14px;} +.sig-ev .up-cell{margin:0;} +.sig-none{color:var(--ink-2);padding:10px 0;font-size:12.5px;} .up-h .src-err{color:var(--stop);font-weight:400;font-size:11.5px;} .mr-two{display:grid;grid-template-columns:1fr 1fr;gap:16px;font-size:12.5px;} .mr-row{padding:3px 0;border-bottom:1px solid var(--hair);} @@ -231,72 +263,156 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius: {{ L.label }} {{ levelCount(L.key) }} 点一下切换显隐,只前端过滤、不查后端 -
-
-
{{ g.label }} · {{ g.items.length }}
- - - - - - -
- + + +
-
决策系统 买/卖 · 读取失败:{{ usrc('intraday').error }}
- - - - - +
mtf 资金异动 · {{ SIG.metrics.length }} · 读取失败
+
+
+ {{ nm(r.ts_code) }}{{ r.ts_code }} + {{ flowText(r.direction) }} + + {{ moneyCn(r.window_net) }} + {{ zBand(r.z_dd).label }} +
+
暂无资金异动
+
+
强度=横截面异动 z_dd:显著(2–3) · 强(3–5) · 极强(≥5)。悬停看原始 z。
- -
-
盘中择时层 · BUY 入场 · 读取失败
- - - - - - -
- -
-
mtf 资金异动 · 读取失败
- - - - - - -
- -
-
决策系统 · 风控卖出 · 读取失败
- - - - - - -
-
mtf 实况分 · 关注 / 回避榜 · 读取失败
-
+
关注(高分)
-
{{ nm(r.ts_code) }} {{ r.ts_code }}{{ r.score }}
-
暂无
+
{{ nm(r.ts_code) }} {{ r.ts_code }}{{ r.score }}
+
暂无
回避(低分)
-
{{ nm(r.ts_code) }} {{ r.ts_code }}{{ r.score }}
-
暂无
+
{{ nm(r.ts_code) }} {{ r.ts_code }}{{ r.score }}
+
暂无
+
+ +
+
+
决策系统 买/卖 · {{ SIG.decision.length }} · 读取失败
+
+
+ {{ nm(r.ts_code) }}{{ r.ts_code }} + + {{ r.action }} · {{ r.signal_type }} + {{ r.time }} +
+
暂无买卖广播
+
+
+
+
日QRS对称 · {{ SIG.qrs.length }}
+
+
+ {{ nm(r.ts_code) }}{{ r.ts_code }} + {{ r.direction }} + + {{ lvLabel(r.level) }} + {{ r.time }}{{ ageText(r) }} +
+
暂无 QRS 告警
+
+
+
+ + +
+
+
资金分布 · {{ SIG.capital.length }}
+
+
+ {{ nm(r.ts_code) }}{{ r.ts_code }} + {{ r.direction }} + + {{ lvLabel(r.level) }} + {{ r.time }}{{ ageText(r) }} +
+
暂无资金分布告警
+
+
+
+
股价异动 · {{ SIG.price_notice.length }}
+
+
+ {{ nm(r.ts_code) }}{{ r.ts_code }} + {{ r.direction }} + + {{ lvLabel(r.level) }} + {{ r.time }}{{ ageText(r) }} +
+
暂无股价异动
+
+
+
+ + +
+
+
决策系统 · 风控卖出 · {{ SIG.sell.length }}
+
+
+ {{ nm(r.ts_code) }} + SELL {{ r.confidence==null?'':r.confidence }} + + {{ r.time }} +
{{ r.reason }}
+
+
+
+
+
多源升级 · {{ SIG.multi.length }}
+
+
+ {{ nm(r.ts_code) }} + {{ r.direction }} + + {{ lvLabel(r.level) }} + {{ r.time }} +
+
+
+
+
盘中择时层 · BUY 入场 · {{ SIG.timing.length }}
+
+
+ {{ nm(r.ts_code) }} + + 参考价 {{ r.price==null?'—':r.price }} + 置信 {{ r.confidence==null?'—':r.confidence }} + {{ r.time }} +
+
+
+
+
资金流强度 · {{ SIG.money_flow.length }}
+
+
+ {{ nm(r.ts_code) }} + {{ r.direction }} + + {{ lvLabel(r.level) }} + {{ r.time }} +
+
+
+
+ + +
+ 在用 · 今日待触发: + {{ e.label }} + 其他/未登记源 · {{ SIG.other.length }}
@@ -1870,6 +1986,47 @@ createApp({ const lvClass = v => v === 'DANGER' ? 'deny' : ((v === 'WARNING' || v === 'IMPORTANT') ? 'queue' : 'wait'); const flowText = d => d === 'inflow' ? '流入' : (d === 'outflow' ? '流出' : (d || '—')); const flowClass = d => d === 'inflow' ? 'clr-up' : (d === 'outflow' ? 'clr-down' : 'muted'); + // ── 上游信号改版 (2026-08-18): 净额领读 + 强度带 + 按重要度分档 + 待触发条 ── + // 净额折成万/亿 (带正负号); 原始 z 值移进悬浮提示, 正文不堆数字。 + const moneyCn = v => { + if (v === null || v === undefined || v === '') return '—'; + const n = Number(v); if (!isFinite(n)) return '—'; + const s = n < 0 ? '-' : '+', a = Math.abs(n); + if (a >= 1e8) return s + (a / 1e8).toFixed(2) + '亿'; + if (a >= 1e4) return s + Math.round(a / 1e4) + '万'; + return s + Math.round(a); + }; + // 强度带: 横截面异动 z_dd 绝对值分档。显著(2–3) / 强(3–5) / 极强(≥5)。 + const zBand = z => { + const a = Math.abs(Number(z) || 0); + if (a >= 5) return { label: '极强', on: 4 }; + if (a >= 3) return { label: '强', on: 3 }; + if (a >= 2) return { label: '显著', on: 2 }; + return { label: '一般', on: 1 }; + }; + const zBars = z => { const on = zBand(z).on; return [1, 2, 3, 4].map(i => i <= on); }; + const dirUp = d => ['看涨', '涨', 'inflow', '流入'].includes(d); + // 一处组装: 各信号当前条目 (告警按级别筛选后的口径, 与筛选条联动)。 + // 已下线的 volume(放量异动) 不再单列 —— 若流里还有历史残留键, 归入 other。 + const SIG = computed(() => { + const up = upstream.value.sources || {}; + const by = {}; for (const a of alertItemsF.value) (by[a.cat] || (by[a.cat] = [])).push(a); + const KNOWN = new Set(['money_flow', 'capital', 'qrs', 'multi', 'price_notice']); + const other = []; Object.keys(by).forEach(k => { if (!KNOWN.has(k)) other.push(...(by[k] || [])); }); + return { + decision: ((up.intraday || {}).decision) || [], timing: ((up.intraday || {}).timing) || [], + sell: ((up.sell_actions || {}).items) || [], multi: by.multi || [], + metrics: ((up.metrics || {}).items) || [], qrs: by.qrs || [], capital: by.capital || [], + money_flow: by.money_flow || [], price_notice: by.price_notice || [], + mr: up.mr || { watch: [], avoid: [] }, other, + }; + }); + // 改版二 (2026-08-18): 六个常用框固定成对常驻; 四个稀有/条件触发信号进"事件"区, + // 触发了出卡、没触发的收进一条待触发条。money_flow(资金流强度)频繁为空, 归入事件区。 + const EVENT_SIGS = [ + { key: 'sell', label: '决策系统 风控卖出' }, { key: 'multi', label: '多源升级' }, + { key: 'timing', label: '盘中择时层 BUY 入场' }, { key: 'money_flow', label: '资金流强度' }]; + const eventsQuiet = computed(() => EVENT_SIGS.filter(e => !SIG.value[e.key].length)); // 告警固定分类格子: 6 类常驻 + 其他(catch-all), 永远这几个框、空的显示暂无 —— 不再随数据冒出冒消。 const ALERT_CATS_FIXED = [ { key:'money_flow', label:'资金流强度' }, { key:'capital', label:'资金分布' }, { key:'qrs', label:'日QRS对称' }, @@ -2194,7 +2351,8 @@ createApp({ upstream, showUpstream, usrc, loadUpstream, showAlerts, alertItems, alertLatest, alertLevelClass, alertGroups, alertStripItems, alertStripCount, alertTotalCount, catShown, toggleCat, ageText, alertRowClass, - alertItemsF, levelShown, toggleLevel, levelCount, ALERT_LEVELS, lvLabel, lvClass, alertGridFixed, passLevel, flowText, flowClass }; + alertItemsF, levelShown, toggleLevel, levelCount, ALERT_LEVELS, lvLabel, lvClass, alertGridFixed, passLevel, flowText, flowClass, + SIG, moneyCn, zBand, zBars, dirUp, eventsQuiet }; } }).use(ElementPlus).mount('#app');