diff --git a/DEVLOG.md b/DEVLOG.md
index 4633f56..ba0e4ce 100644
--- a/DEVLOG.md
+++ b/DEVLOG.md
@@ -50,6 +50,9 @@ app/services/strategy_advisor.py(新增);app/services/strategy_service.py
**真机判收**
部分判收(2026-08-25 盘中)。桥机 make deploy + make test 见 ALL SUITES PASS;dry-run 试算真机四票读数全部合理:688802.SH 想挂网格但「按投入比例折出 47,250 元买不起一手」被挡(科创板高价票,判定正确);002179.SZ 有在途指令主动让路;其余两票无信号静默跳过;unknown_states 为空(子串归类修对了)。**尚未判收的**:真挂一条(等在途清了重扫或次日 09:40)、边三/边四真机走一遍、strategy_runner 对自动网格的逐档发单。
+**次日午间第七批(2026-08-26):布局重设计——撤掉双栏,改「持仓全宽 + 信号速览带 + 信号中心收起」**
+第六批的左右双栏上真机即被否:持仓表被压窄到操作列整个被切掉;信号卡片本是全宽设计,塞进右栏后股票名逐字竖排;右栏比左栏长数倍,「同屏盯两块」根本没实现。重新分析:交易员要随时看的不是整个信号中心(几百条,翻查用),而是与决策相关的信号——尤其持仓票的信号。重做为融合式三层:一,持仓表恢复全宽(操作列回来),并新增「今日信号」列——每只持仓票显示今天与它相关的最新信号(类别、方向、时刻,多条显示 +N,悬停看前三条),信号出现在交易员本来就在看的那一行上;二,持仓表下方新增全宽「信号速览」带——持仓票的信号置顶标「持仓」,其余只收重要与警告级,决策系统买卖、风控卖出、择时入场三路独立信号一并汇入,一行一条按时间倒序,高度受控内部滚动,右上角一键展开完整信号中心;三,完整信号中心整块移到「今日在办」之后、默认收起,卡片恢复全宽可读。区块顺序:持仓 → 信号速览 → 策略 → 今日在办 → 信号中心。全量 560 例通过。
+
**次日上午第六批(2026-08-26):前端文字整改与双栏布局(用户三条标准)**
用户定下三条标准并全页执行:交易员可读且含义明确;开发人员口吻的文字彻底清除;系统文字最大限度精简,提示能删则删、必须留的进悬浮问号不占版面。整改清单:删掉「随便点」「只是看一眼」这类不严肃表述,预演说明并入按钮旁的悬浮提示;预演结果头行压成「预演结果(未执行)· 查 N 只持仓」;执行状态行改为「今日自动挂载已于 09:41 执行:查 4 · 挂载 0 · 被挡 1 · 跳过 1」句式;颜色约定整条彩字图例压成一个悬浮问号;告警级别筛选的「只前端过滤、不查后端」删除改悬浮;上游信号来源行去掉内部代号(mtf);操作日志说明收紧为一句;空策略引导语改严肃措辞;后端返回里会显示到页面的英文类型码全部换成中文名(网格、跟踪止盈、做T)。布局:交易员视图改双栏栅格(左七右五)——左栏持仓加策略,右栏上游信号常驻展开,两边可同屏实时盯;窗口窄于 1500 像素自动叠回单栏,其余区块次序不变。全量 560 例通过。
diff --git a/app/web/static/index.html b/app/web/static/index.html
index 445431b..dcc6f5f 100644
--- a/app/web/static/index.html
+++ b/app/web/static/index.html
@@ -57,10 +57,11 @@ body{margin:0;background:var(--plane);color:var(--ink);
.m .v{color:var(--ink);font-size:21px;font-weight:680;margin-top:5px;letter-spacing:-.2px;font-variant-numeric:tabular-nums;}
.m .v .muted,.m .v span{font-weight:500;}
.m .v.up{color:var(--up);} .m .v.down{color:var(--down);}
-/* 双栏布局: 持仓与策略在左、上游信号在右 (2026-08-26) */
-.tcols{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);gap:12px;align-items:start}
-@media (max-width:1500px){.tcols{grid-template-columns:minmax(0,1fr)}}
-.tcol{min-width:0}
+/* 信号速览带 (2026-08-26): 全宽紧凑行, 高度受控内部滚动 */
+.sigbrief{max-height:216px;overflow:auto}
+.sb-row{display:flex;gap:8px;align-items:center;padding:2px 0;border-bottom:1px dashed rgba(128,128,128,.18)}
+.sb-row:last-child{border-bottom:none}
+.sb-t{width:46px;flex:none;font-size:11.5px}
/* 颜色约定图例 */
.legend{display:flex;gap:15px;flex-wrap:wrap;align-items:center;color:var(--muted);font-size:12px;margin:0 2px 16px;}
.legend .sw{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:4px;vertical-align:middle;}
@@ -298,7 +299,7 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
· 读取失败:{{ usrc('alerts').error }}
· 暂无告警
- 下方查看全部 ▾
+ 完整信号中心 ▾
@@ -348,8 +349,6 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
-
-
我的持仓 · {{ heldPositions.length }} 只
@@ -398,6 +397,21 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
{{ tx('cushion', s.row.cushion_state) }}
{{ pct(s.row.cushion_pct) }} · 连负{{ s.row.neg_cushion_days }}日
+
+
+
+
+
+ {{ heldSigOf(s.row.ts_code)[0].cat }} {{ heldSigOf(s.row.ts_code)[0].direction || '' }}
+ {{ heldSigOf(s.row.ts_code)[0].time }}
+
+ +{{ heldSigOf(s.row.ts_code).length-1 }}
+
+
+ —
+
+
{{ tx('posStatus', s.row.status) }}
{{ tx('frozen', s.row.frozen_reason) }}
@@ -423,6 +437,24 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
+
+
+
信号速览 · {{ sigBrief.length }} 条,持仓相关 {{ sigBriefHeldCount }} 条
+ 完整信号中心 ▾
+
持仓票今日暂无信号,全场暂无重要或警告级信号。
+
+
+ {{ g.time || '—' }}
+ 持仓
+ {{ nm(g.ts_code) }}{{ g.ts_code }}
+ {{ g.cat }}
+ {{ g.direction || '' }}
+ {{ lvLabel(g.level) }}
+ 陈旧
+
+
+
我的策略 · {{ strategies.length }} 个
@@ -525,9 +557,61 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
-
-
+
+
+
今日在办
+
今天下出去的买卖单,按状态分三档:还在跑的、已成交的、已经结束的。
+
+
+ 在办中 {{ insLive.length }}
+
+ {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
+ {{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}
+ {{ s.row.qty }} / {{ s.row.exec_qty||0 }}
+ {{ s.row.limit_price||'—' }}
+ {{ tx('insStatus', s.row.status) }}
+
+
+
+
+ 今日成交 {{ insDone.length }}
+
+ {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
+ {{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}
+ {{ s.row.qty }} / {{ s.row.exec_qty||0 }}
+ {{ tx('insStatus', s.row.status) }}
+
+
+
+ 已了结 {{ insEnd.length }}
+
+ {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
+ {{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}
+ {{ tx('insStatus', s.row.status) }}
+
+
+
+ 今日否决 {{ denyToday.length }}
+ 今天考察过、但没建仓的票,连原因一起摆出来。
+
+ {{ s.row.name }} {{ s.row.ts_code }}
+ {{ s.row.why || '—' }}
+
+
+
+
今天发生了什么 · {{ ledger.length }} 条 {{ showLedger?'▲ 收起':'▼ 展开' }}
+
+ 今天还没有记录。
+
+ {{ (l.decided_at||'').slice(11,16) }}
+ {{ nm(l.ts_code) }}:{{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }} —— {{ l.reason }}
+
+
+
+
+
+
上游信号 · 只读参考,不进下单逻辑 {{ showUpstream?'▲ 收起':'▼ 展开' }}
最近取数 {{ (upstream.at||'').slice(11,19) }} · 来源:决策系统 / 盘中择时
@@ -696,59 +780,6 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
-
-
-
-
-
今日在办
-
今天下出去的买卖单,按状态分三档:还在跑的、已成交的、已经结束的。
-
-
- 在办中 {{ insLive.length }}
-
- {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
- {{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}
- {{ s.row.qty }} / {{ s.row.exec_qty||0 }}
- {{ s.row.limit_price||'—' }}
- {{ tx('insStatus', s.row.status) }}
-
-
-
-
- 今日成交 {{ insDone.length }}
-
- {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
- {{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}
- {{ s.row.qty }} / {{ s.row.exec_qty||0 }}
- {{ tx('insStatus', s.row.status) }}
-
-
-
- 已了结 {{ insEnd.length }}
-
- {{ nm(s.row.ts_code) }} {{ s.row.ts_code }}
- {{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}
- {{ tx('insStatus', s.row.status) }}
-
-
-
- 今日否决 {{ denyToday.length }}
- 今天考察过、但没建仓的票,连原因一起摆出来。
-
- {{ s.row.name }} {{ s.row.ts_code }}
- {{ s.row.why || '—' }}
-
-
-
-
今天发生了什么 · {{ ledger.length }} 条 {{ showLedger?'▲ 收起':'▼ 展开' }}
-
- 今天还没有记录。
-
- {{ (l.decided_at||'').slice(11,16) }}
- {{ nm(l.ts_code) }}:{{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }} —— {{ l.reason }}
-
-
-
@@ -1648,7 +1679,7 @@ createApp({
const lastRefresh = ref('');
const autoRefresh = ref(true);
const upstream = ref({ sources: {} });
- const showUpstream = ref(true); // 双栏后信号在右栏常驻显示, 点标题可折叠 (2026-08-26)
+ const showUpstream = ref(false); // 信号中心默认收起; 常驻速览带在持仓下方 (2026-08-26)
const showAlerts = ref(false);
const alertShowMap = reactive({ money_flow:true, capital:true, qrs:true, volume:true, multi:true, price_notice:false, buy_emitted:false, other:true });
// 级别筛选记忆: 存 sessionStorage —— 普通刷新保留, 关标签页/新开标签=回默认。默认关 普通/提示。
@@ -2207,6 +2238,46 @@ createApp({
const alertLatest = computed(() => alertStripItems.value[0] || {});
const alertStripCount = computed(() => alertStripItems.value.length);
const alertTotalCount = computed(() => alertItems.value.length);
+ // ── 信号速览 (2026-08-26 重设计): 交易员要随时看到的不是整个信号中心, 而是
+ // 「持仓票的信号 + 全场重要/警告级」。持仓票置顶; 决策系统买卖/风控卖出/择时
+ // 入场三路独立信号也并进来, 免得只看告警漏了真正会动手的那几条。 ──
+ const code6 = s => (String(s || '').match(/\d{6}/) || [''])[0];
+ const heldCodeSet = computed(() => new Set(heldPositions.value.map(p => code6(p.ts_code))));
+ const sigBrief = computed(() => {
+ const held = heldCodeSet.value;
+ const out = [];
+ for (const a of alertItems.value) {
+ const isHeld = held.has(code6(a.ts_code));
+ if (!isHeld && !['DANGER', 'WARNING'].includes(normLv(a.level))) continue;
+ out.push({ ts_code: a.ts_code, time: a.time || '', cat: a.cat_label || a.cat,
+ direction: a.direction, level: a.level, held: isHeld, stale: a.stale });
+ }
+ const s = SIG.value;
+ for (const r of (s.sell || [])) out.push({
+ ts_code: r.ts_code, time: r.time || '', cat: '风控卖出',
+ direction: '卖出', level: 'DANGER', held: held.has(code6(r.ts_code)) });
+ for (const r of (s.decision || [])) out.push({
+ ts_code: r.ts_code, time: r.time || '', cat: '决策系统',
+ direction: r.action === 'SELL' ? '卖出' : '买入', level: 'WARNING',
+ held: held.has(code6(r.ts_code)) });
+ for (const r of (s.timing || [])) out.push({
+ ts_code: r.ts_code, time: r.time || '', cat: '择时入场',
+ direction: '买入', level: 'INFO', held: held.has(code6(r.ts_code)) });
+ out.sort((a, b) => (b.held - a.held) || String(b.time).localeCompare(String(a.time)));
+ return out;
+ });
+ const sigBriefHeldCount = computed(() => sigBrief.value.filter(x => x.held).length);
+ const heldSigMap = computed(() => {
+ const m = {};
+ for (const x of sigBrief.value) {
+ if (!x.held) continue;
+ const k = code6(x.ts_code);
+ (m[k] || (m[k] = [])).push(x);
+ }
+ return m;
+ });
+ function heldSigOf(code) { return heldSigMap.value[code6(code)] || []; }
+ function openSigCenter() { showUpstream.value = true; scrollTo('t-sig'); }
const alertLevelClass = computed(() => {
const it = alertStripItems.value;
if (it.some(x => normLv(x.level) === 'DANGER')) return 'strong';
@@ -2590,6 +2661,7 @@ createApp({
showAlerts, alertItems, alertLatest, alertLevelClass, alertGroups, alertStripItems,
alertStripCount, alertTotalCount, catShown, toggleCat, ageText, alertRowClass,
alertItemsF, levelShown, toggleLevel, sellOpen, toggleSell, levelCount, ALERT_LEVELS, lvLabel, lvClass, alertGridFixed, passLevel, flowText, flowClass,
+ sigBrief, sigBriefHeldCount, heldSigOf, openSigCenter,
SIG, moneyCn, zBand, zBars, dirUp, eventsQuiet };
}
}).use(ElementPlus).mount('#app');