开始处理系统整体细节
This commit is contained in:
parent
3a02bc00ff
commit
82ab9ed5c1
48
DEVLOG.md
48
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 · 清仓择时改造:紧急直通 + 卖出分桶收口 + 自主卖出窗口不作废
|
## 2026-08-17 · 清仓择时改造:紧急直通 + 卖出分桶收口 + 自主卖出窗口不作废
|
||||||
|
|
||||||
**做了什么**
|
**做了什么**
|
||||||
|
|
|
||||||
|
|
@ -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-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-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;}
|
.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;}
|
.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-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);}
|
.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:
|
||||||
<span v-for="L in ALERT_LEVELS" :key="L.key" class="lv-chip" :class="levelShown(L.key)?('on lv-'+L.cls):'off'" @click="toggleLevel(L.key)">{{ L.label }} <span style="opacity:.7">{{ levelCount(L.key) }}</span></span>
|
<span v-for="L in ALERT_LEVELS" :key="L.key" class="lv-chip" :class="levelShown(L.key)?('on lv-'+L.cls):'off'" @click="toggleLevel(L.key)">{{ L.label }} <span style="opacity:.7">{{ levelCount(L.key) }}</span></span>
|
||||||
<span class="muted" style="font-size:11px;margin-left:4px">点一下切换显隐,只前端过滤、不查后端</span>
|
<span class="muted" style="font-size:11px;margin-left:4px">点一下切换显隐,只前端过滤、不查后端</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="up-grid">
|
<!-- 常驻盘口: 固定三对, 位置稳定不重排。空的显示暂无, 不再随数据冒出冒消。 -->
|
||||||
<div class="up-cell" v-for="g in alertGridFixed" :key="g.key">
|
<!-- 第一对 (拉高并排): mtf 资金异动 | mtf 实况分 关注/回避榜 —— 两边列表通常长 -->
|
||||||
<div class="up-h">{{ g.label }} <span class="muted" style="font-weight:400">· {{ g.items.length }}</span></div>
|
<div class="sig2 tall">
|
||||||
<el-table :data="g.items.slice(0,20)" size="small" max-height="200" empty-text="暂无" :row-class-name="alertRowClass">
|
|
||||||
<el-table-column label="股票" min-width="140"><template #default="s"><b>{{ nm(s.row.ts_code) }}</b> <span class="muted mono">{{ s.row.ts_code }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="方向" width="56"><template #default="s"><span v-if="s.row.direction && s.row.direction!=='—'" :class="['看涨','涨'].includes(s.row.direction)?'clr-up':'clr-down'">{{ s.row.direction }}</span><span v-else class="muted">—</span></template></el-table-column>
|
|
||||||
<el-table-column label="级别" width="66"><template #default="s"><span class="disp" :class="lvClass(s.row.level)">{{ lvLabel(s.row.level) }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="时间" width="116" align="right"><template #default="s"><span class="mono muted">{{ s.row.time }}</span><span v-if="ageText(s.row)" class="alert-age">{{ ageText(s.row) }}</span></template></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="up-cell">
|
<div class="up-cell">
|
||||||
<div class="up-h">决策系统 买/卖<span class="src-err" v-if="usrc('intraday') && usrc('intraday').ok===false"> · 读取失败:{{ usrc('intraday').error }}</span></div>
|
<div class="up-h">mtf 资金异动 <span class="muted" style="font-weight:400">· {{ SIG.metrics.length }}</span><span class="src-err" v-if="usrc('metrics') && usrc('metrics').ok===false"> · 读取失败</span></div>
|
||||||
<el-table :data="((usrc('intraday')||{}).decision||[]).slice(0,8)" size="small" max-height="200" empty-text="暂无">
|
<div class="sig-rows">
|
||||||
<el-table-column label="股票" min-width="130"><template #default="s"><b>{{ nm(s.row.ts_code) }}</b> <span class="muted mono">{{ s.row.ts_code }}</span></template></el-table-column>
|
<div class="sig-row" v-for="(r,i) in SIG.metrics.slice(0,20)" :key="i" :title="'原始 z_dd = '+(r.z_dd==null?'—':r.z_dd)">
|
||||||
<el-table-column label="信号" width="128"><template #default="s"><span class="disp" :class="s.row.action==='SELL'?'deny':'done'">{{ s.row.action }} · {{ s.row.signal_type }}</span></template></el-table-column>
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span><span class="muted mono" style="font-size:11px">{{ r.ts_code }}</span>
|
||||||
<el-table-column label="时间" width="66" align="right"><template #default="s"><span class="mono muted">{{ s.row.time }}</span></template></el-table-column>
|
<span v-if="flowText(r.direction)!=='—'" :class="dirUp(r.direction)?'clr-up':'clr-down'" style="font-weight:600">{{ flowText(r.direction) }}</span>
|
||||||
</el-table>
|
<span class="sig-sp"></span>
|
||||||
|
<span class="mono" style="font-weight:600" :class="(r.window_net||0)>=0?'clr-up':'clr-down'">{{ moneyCn(r.window_net) }}</span>
|
||||||
|
<span class="intens"><span class="ibar"><i v-for="(on,bi) in zBars(r.z_dd)" :key="bi" :class="on?'on':''"></i></span><span class="mono" style="font-weight:700;font-size:11px" :class="dirUp(r.direction)?'clr-up':'clr-down'">{{ zBand(r.z_dd).label }}</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sig-none" v-if="!SIG.metrics.length">暂无资金异动</div>
|
||||||
<div class="up-cell">
|
|
||||||
<div class="up-h">盘中择时层 · BUY 入场<span class="src-err" v-if="usrc('intraday') && usrc('intraday').ok===false"> · 读取失败</span></div>
|
|
||||||
<el-table :data="((usrc('intraday')||{}).timing||[]).slice(0,8)" size="small" max-height="200" empty-text="暂无">
|
|
||||||
<el-table-column label="股票" min-width="130"><template #default="s"><b>{{ nm(s.row.ts_code) }}</b> <span class="muted mono">{{ s.row.ts_code }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="参考价" width="82" align="right"><template #default="s"><span class="mono">{{ s.row.price==null?'—':s.row.price }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="置信" width="66" align="right"><template #default="s"><span class="mono">{{ s.row.confidence==null?'—':s.row.confidence }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="时间" width="60" align="right"><template #default="s"><span class="mono muted">{{ s.row.time }}</span></template></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="muted" style="font-size:11px;margin-top:6px">强度=横截面异动 z_dd:显著(2–3) · 强(3–5) · 极强(≥5)。悬停看原始 z。</div>
|
||||||
<div class="up-cell">
|
|
||||||
<div class="up-h">mtf 资金异动<span class="src-err" v-if="usrc('metrics') && usrc('metrics').ok===false"> · 读取失败</span></div>
|
|
||||||
<el-table :data="((usrc('metrics')||{}).items||[]).slice(0,8)" size="small" max-height="200" empty-text="暂无">
|
|
||||||
<el-table-column label="股票" min-width="120"><template #default="s"><b>{{ nm(s.row.ts_code) }}</b> <span class="muted mono">{{ s.row.ts_code }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="方向" width="60"><template #default="s"><span v-if="flowText(s.row.direction)!=='—'" :class="flowClass(s.row.direction)">{{ flowText(s.row.direction) }}</span><span v-else class="muted">—</span></template></el-table-column>
|
|
||||||
<el-table-column label="异动z" width="62" align="right"><template #default="s"><span class="mono">{{ s.row.z_dd==null?'—':s.row.z_dd }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="净额" width="98" align="right"><template #default="s"><span class="mono" :class="s.row.window_net==null?'muted':((s.row.window_net||0)>=0?'clr-up':'clr-down')">{{ s.row.window_net==null?'—':money(s.row.window_net) }}</span></template></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="up-cell">
|
|
||||||
<div class="up-h">决策系统 · 风控卖出<span class="src-err" v-if="usrc('sell_actions') && usrc('sell_actions').ok===false"> · 读取失败</span></div>
|
|
||||||
<el-table :data="((usrc('sell_actions')||{}).items||[]).slice(0,8)" size="small" max-height="200" empty-text="暂无">
|
|
||||||
<el-table-column label="股票" min-width="118"><template #default="s"><b>{{ nm(s.row.ts_code) }}</b></template></el-table-column>
|
|
||||||
<el-table-column label="置信" width="60" align="right"><template #default="s"><span class="mono">{{ s.row.confidence==null?'—':s.row.confidence }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="理由" min-width="180"><template #default="s"><span class="muted" style="font-size:12px">{{ s.row.reason || '—' }}</span></template></el-table-column>
|
|
||||||
<el-table-column label="时间" width="56" align="right"><template #default="s"><span class="mono muted">{{ s.row.time }}</span></template></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="up-cell">
|
<div class="up-cell">
|
||||||
<div class="up-h">mtf 实况分 · 关注 / 回避榜<span class="src-err" v-if="usrc('mr') && usrc('mr').ok===false"> · 读取失败</span></div>
|
<div class="up-h">mtf 实况分 · 关注 / 回避榜<span class="src-err" v-if="usrc('mr') && usrc('mr').ok===false"> · 读取失败</span></div>
|
||||||
<div class="mr-two">
|
<div class="mr-two" style="flex:1">
|
||||||
<div>
|
<div>
|
||||||
<div class="muted" style="margin-bottom:5px">关注(高分)</div>
|
<div class="muted" style="margin-bottom:5px">关注(高分)</div>
|
||||||
<div v-for="(r,i) in ((usrc('mr')||{}).watch||[]).slice(0,8)" :key="i" class="mr-row"><b>{{ nm(r.ts_code) }}</b> <span class="muted mono">{{ r.ts_code }}</span><span class="mono" style="float:right;color:var(--accent)">{{ r.score }}</span></div>
|
<div v-for="(r,i) in (SIG.mr.watch||[]).slice(0,14)" :key="i" class="mr-row"><b>{{ nm(r.ts_code) }}</b> <span class="muted mono">{{ r.ts_code }}</span><span class="mono" style="float:right;color:var(--accent)">{{ r.score }}</span></div>
|
||||||
<div class="muted" v-if="!((usrc('mr')||{}).watch||[]).length">暂无</div>
|
<div class="sig-none" v-if="!(SIG.mr.watch||[]).length">暂无</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="muted" style="margin-bottom:5px">回避(低分)</div>
|
<div class="muted" style="margin-bottom:5px">回避(低分)</div>
|
||||||
<div v-for="(r,i) in ((usrc('mr')||{}).avoid||[]).slice(0,8)" :key="i" class="mr-row"><b>{{ nm(r.ts_code) }}</b> <span class="muted mono">{{ r.ts_code }}</span><span class="mono" style="float:right;color:var(--warn)">{{ r.score }}</span></div>
|
<div v-for="(r,i) in (SIG.mr.avoid||[]).slice(0,14)" :key="i" class="mr-row"><b>{{ nm(r.ts_code) }}</b> <span class="muted mono">{{ r.ts_code }}</span><span class="mono" style="float:right;color:var(--warn)">{{ r.score }}</span></div>
|
||||||
<div class="muted" v-if="!((usrc('mr')||{}).avoid||[]).length">暂无</div>
|
<div class="sig-none" v-if="!(SIG.mr.avoid||[]).length">暂无</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 第二对: 决策系统 买/卖 | 日QRS对称 -->
|
||||||
|
<div class="sig2">
|
||||||
|
<div class="up-cell">
|
||||||
|
<div class="up-h">决策系统 买/卖 <span class="muted" style="font-weight:400">· {{ SIG.decision.length }}</span><span class="src-err" v-if="usrc('intraday') && usrc('intraday').ok===false"> · 读取失败</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.decision.slice(0,14)" :key="i">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span><span class="muted mono" style="font-size:11px">{{ r.ts_code }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="disp" :class="r.action==='SELL'?'deny':'done'">{{ r.action }} · {{ r.signal_type }}</span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sig-none" v-if="!SIG.decision.length">暂无买卖广播</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="up-cell">
|
||||||
|
<div class="up-h">日QRS对称 <span class="muted" style="font-weight:400">· {{ SIG.qrs.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.qrs.slice(0,14)" :key="i" :class="r.stale?'alert-stale':''">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span><span class="muted mono" style="font-size:11px">{{ r.ts_code }}</span>
|
||||||
|
<span v-if="r.direction && r.direction!=='—'" :class="dirUp(r.direction)?'clr-up':'clr-down'" style="font-weight:600">{{ r.direction }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="disp" :class="lvClass(r.level)">{{ lvLabel(r.level) }}</span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span><span v-if="ageText(r)" class="alert-age">{{ ageText(r) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sig-none" v-if="!SIG.qrs.length">暂无 QRS 告警</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第三对: 资金分布 | 股价异动 -->
|
||||||
|
<div class="sig2">
|
||||||
|
<div class="up-cell">
|
||||||
|
<div class="up-h">资金分布 <span class="muted" style="font-weight:400">· {{ SIG.capital.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.capital.slice(0,14)" :key="i" :class="r.stale?'alert-stale':''">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span><span class="muted mono" style="font-size:11px">{{ r.ts_code }}</span>
|
||||||
|
<span v-if="r.direction && r.direction!=='—'" :class="dirUp(r.direction)?'clr-up':'clr-down'" style="font-weight:600">{{ r.direction }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="disp" :class="lvClass(r.level)">{{ lvLabel(r.level) }}</span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span><span v-if="ageText(r)" class="alert-age">{{ ageText(r) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sig-none" v-if="!SIG.capital.length">暂无资金分布告警</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="up-cell">
|
||||||
|
<div class="up-h">股价异动 <span class="muted" style="font-weight:400">· {{ SIG.price_notice.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.price_notice.slice(0,14)" :key="i" :class="r.stale?'alert-stale':''">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span><span class="muted mono" style="font-size:11px">{{ r.ts_code }}</span>
|
||||||
|
<span v-if="r.direction && r.direction!=='—'" :class="dirUp(r.direction)?'clr-up':'clr-down'" style="font-weight:600">{{ r.direction }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="disp" :class="lvClass(r.level)">{{ lvLabel(r.level) }}</span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span><span v-if="ageText(r)" class="alert-age">{{ ageText(r) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sig-none" v-if="!SIG.price_notice.length">暂无股价异动</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 事件信号 (稀有/条件触发): 触发了出卡, 没触发的收成一条待触发 -->
|
||||||
|
<div class="sig-ev" v-if="SIG.sell.length || SIG.multi.length || SIG.timing.length || SIG.money_flow.length">
|
||||||
|
<div class="up-cell" v-if="SIG.sell.length">
|
||||||
|
<div class="up-h" style="color:var(--stop)">决策系统 · 风控卖出 <span class="muted" style="font-weight:400">· {{ SIG.sell.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.sell.slice(0,10)" :key="i" style="flex-wrap:wrap">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span>
|
||||||
|
<span class="disp deny">SELL {{ r.confidence==null?'':r.confidence }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span>
|
||||||
|
<div style="flex-basis:100%;font-size:12px;line-height:1.4" class="muted" v-if="r.reason">{{ r.reason }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="up-cell" v-if="SIG.multi.length">
|
||||||
|
<div class="up-h" style="color:var(--stop)">多源升级 <span class="muted" style="font-weight:400">· {{ SIG.multi.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.multi.slice(0,10)" :key="i" :class="r.stale?'alert-stale':''">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span>
|
||||||
|
<span v-if="r.direction && r.direction!=='—'" :class="dirUp(r.direction)?'clr-up':'clr-down'" style="font-weight:600">{{ r.direction }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="disp" :class="lvClass(r.level)">{{ lvLabel(r.level) }}</span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="up-cell" v-if="SIG.timing.length">
|
||||||
|
<div class="up-h">盘中择时层 · BUY 入场 <span class="muted" style="font-weight:400">· {{ SIG.timing.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.timing.slice(0,10)" :key="i">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="muted" style="font-size:12px">参考价 <span class="mono" style="color:var(--ink)">{{ r.price==null?'—':r.price }}</span></span>
|
||||||
|
<span class="muted" style="font-size:12px">置信 <span class="mono" style="color:var(--ink)">{{ r.confidence==null?'—':r.confidence }}</span></span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="up-cell" v-if="SIG.money_flow.length">
|
||||||
|
<div class="up-h">资金流强度 <span class="muted" style="font-weight:400">· {{ SIG.money_flow.length }}</span></div>
|
||||||
|
<div class="sig-rows">
|
||||||
|
<div class="sig-row" v-for="(r,i) in SIG.money_flow.slice(0,10)" :key="i" :class="r.stale?'alert-stale':''">
|
||||||
|
<span class="sig-nm">{{ nm(r.ts_code) }}</span>
|
||||||
|
<span v-if="r.direction && r.direction!=='—'" :class="dirUp(r.direction)?'clr-up':'clr-down'" style="font-weight:600">{{ r.direction }}</span>
|
||||||
|
<span class="sig-sp"></span>
|
||||||
|
<span class="disp" :class="lvClass(r.level)">{{ lvLabel(r.level) }}</span>
|
||||||
|
<span class="mono muted" style="font-size:11px">{{ r.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 待触发条: 空的事件信号 + 资金流强度 + 其他桶, 收成一条 armed 待命 -->
|
||||||
|
<div class="armed" style="margin-top:14px" v-if="eventsQuiet.length || SIG.other.length">
|
||||||
|
<span class="lead">在用 · 今日待触发:</span>
|
||||||
|
<span class="chip" v-for="e in eventsQuiet" :key="e.key"><span class="dot"></span>{{ e.label }}</span>
|
||||||
|
<span class="chip" v-if="SIG.other.length" style="border-color:var(--warn)"><span class="dot" style="background:var(--warn)"></span>其他/未登记源 · {{ SIG.other.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1870,6 +1986,47 @@ createApp({
|
||||||
const lvClass = v => v === 'DANGER' ? 'deny' : ((v === 'WARNING' || v === 'IMPORTANT') ? 'queue' : 'wait');
|
const lvClass = v => v === 'DANGER' ? 'deny' : ((v === 'WARNING' || v === 'IMPORTANT') ? 'queue' : 'wait');
|
||||||
const flowText = d => d === 'inflow' ? '流入' : (d === 'outflow' ? '流出' : (d || '—'));
|
const flowText = d => d === 'inflow' ? '流入' : (d === 'outflow' ? '流出' : (d || '—'));
|
||||||
const flowClass = d => d === 'inflow' ? 'clr-up' : (d === 'outflow' ? 'clr-down' : 'muted');
|
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), 永远这几个框、空的显示暂无 —— 不再随数据冒出冒消。
|
// 告警固定分类格子: 6 类常驻 + 其他(catch-all), 永远这几个框、空的显示暂无 —— 不再随数据冒出冒消。
|
||||||
const ALERT_CATS_FIXED = [
|
const ALERT_CATS_FIXED = [
|
||||||
{ key:'money_flow', label:'资金流强度' }, { key:'capital', label:'资金分布' }, { key:'qrs', label:'日QRS对称' },
|
{ key:'money_flow', label:'资金流强度' }, { key:'capital', label:'资金分布' }, { key:'qrs', label:'日QRS对称' },
|
||||||
|
|
@ -2194,7 +2351,8 @@ createApp({
|
||||||
upstream, showUpstream, usrc, loadUpstream,
|
upstream, showUpstream, usrc, loadUpstream,
|
||||||
showAlerts, alertItems, alertLatest, alertLevelClass, alertGroups, alertStripItems,
|
showAlerts, alertItems, alertLatest, alertLevelClass, alertGroups, alertStripItems,
|
||||||
alertStripCount, alertTotalCount, catShown, toggleCat, ageText, alertRowClass,
|
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');
|
}).use(ElementPlus).mount('#app');
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue