修改前端页面
This commit is contained in:
parent
e794d8520d
commit
8372c388a3
|
|
@ -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 只持仓」;执行状态行改为「今日自动挂载已于 09:41 执行:查 4 · 挂载 0 · 被挡 1 · 跳过 1」句式;颜色约定整条彩字图例压成一个悬浮问号;告警级别筛选的「只前端过滤、不查后端」删除改悬浮;上游信号来源行去掉内部代号(mtf);操作日志说明收紧为一句;空策略引导语改严肃措辞;后端返回里会显示到页面的英文类型码全部换成中文名(网格、跟踪止盈、做T)。布局:交易员视图改双栏栅格(左七右五)——左栏持仓加策略,右栏上游信号常驻展开,两边可同屏实时盯;窗口窄于 1500 像素自动叠回单栏,其余区块次序不变。全量 560 例通过。
|
||||
|
||||
**次日上午第五批(2026-08-26 盘中):把「预演」与「正式跑」在页面上分清**
|
||||
用户反馈「试算只判断」的提示看不懂到底有用没用——根子是页面只有预演镜,没人回答「今天的正式一跳跑没跑、做了什么」,而零动作的一跳在台账上没有任何痕迹(设计如此,台账只记真动作)。补法:advisor 每次真跑(含总开关关着的那次)在每个出口写一份摘要进运行参数(新登记 PMS_AUTO_LAST_SCAN,写失败只告警;set_param 返回值按纪律接住),策略接口把总开关状态、今天跑没跑、各类计数一并返回;页面「我的策略」常驻一行仪表:「今天的正式一跳已在 09:41 跑过:查 4 只,挂载 0、被挡 1、跳过 1」或「还没跑(09:40 自动执行)」,按钮改名「预演 · 现在系统想做什么」,预演结果头一句明说「什么都没动」。批十七加一例钉住「真跑每个出口都写、预演一笔不写」,总数 560。
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ STG_DISTRIB, STG_REPAIR, STG_NEUTRAL = "高位派发", "深亏修复", "中性"
|
|||
ACCUM_WINDOW_DAYS = 45 # 每票取近 45 自然日内最新一条结论
|
||||
HEAT_MAX_AGE_DAYS = 4 # 热度表末日落后超此自然日 → 热度信号本轮不可用
|
||||
_RULE_OF_TYPE = {"GRID": R_GRID, "TRAIL": R_TRAIL}
|
||||
_CN_TYPE = {"GRID": "网格", "TRAIL": "跟踪止盈", "T0": "做T"} # 页面文案用中文名, 不给交易员看代码
|
||||
|
||||
|
||||
def lot_of(ts_code) -> int:
|
||||
|
|
@ -496,7 +497,7 @@ def scan(*, dry_run: bool = False, now=None) -> dict:
|
|||
heat_th=prm["heat_th"], cushion=p.get("cushion_pct"),
|
||||
stype=(st or {}).get("type"), is_auto=is_auto)
|
||||
if st and not is_auto:
|
||||
stg_why += " (挂着人工策略, 自动挂载不碰)"
|
||||
stg_why += " (人工策略, 自动挂载不介入)"
|
||||
out["stages"].append({"ts_code": code, "stage": stg, "why": stg_why,
|
||||
"accum_state": a.get("state"), "heat": hv,
|
||||
"cushion_pct": p.get("cushion_pct"),
|
||||
|
|
@ -530,7 +531,8 @@ def _tend_existing(st, p, a, fresh, hv, prm, buypause, handoff_cool, today,
|
|||
is_auto = note.startswith("自动挂载")
|
||||
stype = str(st.get("type") or "").upper()
|
||||
if not is_auto:
|
||||
out["skipped"].append({"ts_code": code, "why": f"挂着人工策略 ({stype}), 自动挂载不碰它"})
|
||||
out["skipped"].append({"ts_code": code, "why":
|
||||
f"挂着人工策略({_CN_TYPE.get(stype, stype)}), 自动挂载不介入"})
|
||||
return
|
||||
if stype == "GRID":
|
||||
# ---- 边四: 接力切换 (先于边三判 —— 都成立时说明已在拉升, 换止盈比停买更对) ----
|
||||
|
|
@ -583,7 +585,8 @@ def _tend_existing(st, p, a, fresh, hv, prm, buypause, handoff_cool, today,
|
|||
elif r.get("error"):
|
||||
out["errors"].append(f"{code} 解除买入暂停失败: {r['error']}")
|
||||
else:
|
||||
out["skipped"].append({"ts_code": code, "why": f"已挂自动 {stype}, 本轮无事"})
|
||||
out["skipped"].append({"ts_code": code,
|
||||
"why": f"已挂自动{_CN_TYPE.get(stype, stype)}, 本轮无需变更"})
|
||||
|
||||
|
||||
def _attach_one(edge, why, p, a, hv, prm, view, black, live_codes, optout,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ 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}
|
||||
/* 颜色约定图例 */
|
||||
.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;}
|
||||
|
|
@ -297,16 +301,241 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
|
|||
<span class="muted" style="font-size:11.5px;cursor:pointer" @click="showUpstream=true">下方查看全部 ▾</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- 1) 今日一览 + 需要注意 -->
|
||||
<div class="metrics">
|
||||
<div class="m"><div class="k">账户总资产</div><div class="v">{{ money(ov.total_asset) }}</div></div>
|
||||
<div class="m"><div class="k">可用资金<span class="muted" v-if="ov.cash_source!=='ws'"> (估算)</span></div>
|
||||
<div class="v" :class="ov.cash_source==='ws'?'':'muted'">{{ money(ov.cash_source==='ws' ? ov.cash_avail : ov.cash_est) }}</div></div>
|
||||
<div class="m"><div class="k">持仓市值</div><div class="v">{{ money(ov.portfolio_mv) }}</div></div>
|
||||
<div class="m"><div class="k">仓位</div><div class="v">{{ pct(ov.portfolio_pct) }}<span class="muted"> / {{ pct(ov.portfolio_cap) }}</span></div></div>
|
||||
<div class="m"><div class="k">浮动盈亏</div>
|
||||
<div class="v" :class="(ov.float_pnl||0)>=0?'up':'down'">{{ money(ov.float_pnl) }}<span style="font-size:13px"> {{ ov.float_pnl_pct==null?'':pct(ov.float_pnl_pct) }}</span></div></div>
|
||||
<div class="m"><div class="k">持仓数</div><div class="v">{{ ov.names_count }}<span class="muted"> / {{ ov.max_names }}</span></div></div>
|
||||
<div class="m" style="cursor:pointer" @click="scrollTo('t-prop')"><div class="k">等我拍板</div>
|
||||
<div class="v" :class="proposals.length?'up':''">{{ proposals.length }} 条</div></div>
|
||||
<div class="m"><div class="k">自主档位</div><div class="v" style="font-size:15px">{{ tx('autonomy', ov.autonomy) }}</div></div>
|
||||
</div>
|
||||
<div class="legend"><span>颜色约定</span><span class="help" data-tip="红=涨/盈;绿=跌/亏;琥珀=需注意;橙=被拦下;蓝=正常/可操作。红绿只用于价格与盈亏,系统状态用蓝/琥珀/橙/灰。">?</span></div>
|
||||
|
||||
<div class="panel" v-if="attention.length" style="border-color:#7a5b1e">
|
||||
<h3 style="color:#e6a23c">需要注意</h3>
|
||||
<div v-for="(a,i) in attention" :key="i" class="attn">· {{ a }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 2) 等我拍板 -->
|
||||
<div class="panel tblk" id="t-prop">
|
||||
<h3>等我拍板 · {{ proposals.length }} 条</h3>
|
||||
<div class="muted" v-if="!proposals.length">暂无需要你确认的提议。</div>
|
||||
<div v-for="p in proposals" :key="p.proposal_id" class="tcard">
|
||||
<div class="row" style="justify-content:space-between">
|
||||
<div><b style="font-size:15px">{{ nm(p.ts_code) }}</b> <span class="muted mono">{{ p.ts_code }}</span>
|
||||
<el-tag size="small" effect="dark" type="primary" style="margin-left:8px">{{ tx('action', p.action) }}</el-tag></div>
|
||||
<div class="muted">{{ p.expire_at }} 前有效</div>
|
||||
</div>
|
||||
<div style="margin:6px 0" v-if="p.judge_reason"><span class="muted">决策系统:</span>{{ p.judge_reason }}</div>
|
||||
<div class="muted" style="margin:4px 0">{{ propWhy(p) }}</div>
|
||||
<div class="row" style="margin-top:6px">
|
||||
<span class="muted">约 {{ p.qty }} 股 · 参考价 {{ (p.hard_numbers||{}).price==null ? '—' : (p.hard_numbers||{}).price }}
|
||||
· 约需 {{ money(((p.hard_numbers||{}).price||0)*(p.qty||0)) }}</span>
|
||||
<div class="spacer"></div>
|
||||
<el-button type="success" size="small" @click="decide(p,'ACCEPTED')">采纳</el-button>
|
||||
<el-button type="danger" size="small" @click="decide(p,'DECLINED')">驳回</el-button>
|
||||
</div>
|
||||
<div class="muted" style="font-size:11px;margin-top:4px">采纳=记一笔待执行指令,由择时在窗口内择机下单;驳回=今日不再提这只。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3) 我的持仓 -->
|
||||
<!-- 双栏 (2026-08-26 用户定): 左=持仓+策略, 右=上游信号, 两边都要实时盯; 窄屏自动叠回单栏 -->
|
||||
<div class="tcols"><div class="tcol">
|
||||
<div class="panel tblk" id="t-pos">
|
||||
<h3>我的持仓 · {{ heldPositions.length }} 只</h3>
|
||||
<el-table :data="heldPositions" size="small" border max-height="460" @expand-change="onPosExpand">
|
||||
<el-table-column type="expand">
|
||||
<template #default="s">
|
||||
<div class="pos-exp">
|
||||
<div>
|
||||
<div class="exp-h">持仓批次</div>
|
||||
<el-table v-if="lotsOf===s.row.ts_code && lots.length" :data="lots" size="small">
|
||||
<el-table-column label="批次" min-width="84"><template #default="l">{{ tx('lot', l.row.lot_type) }}</template></el-table-column>
|
||||
<el-table-column prop="qty" label="剩余" width="72" align="right"></el-table-column>
|
||||
<el-table-column prop="open_price" label="开仓价" width="80" align="right"></el-table-column>
|
||||
<el-table-column prop="open_date" label="开仓日" width="104"></el-table-column>
|
||||
<el-table-column prop="realized_pnl" label="已实现" width="84" align="right"></el-table-column>
|
||||
</el-table>
|
||||
<div class="muted" v-else-if="lotsOf===s.row.ts_code" style="padding:4px 0">无持仓批次</div>
|
||||
<div class="muted" v-else style="padding:4px 0">载入中…</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="exp-h">该股账本</div>
|
||||
<div class="muted" v-if="!ledger.filter(x=>x.ts_code===s.row.ts_code).length" style="padding:4px 0">今日暂无记录</div>
|
||||
<div v-for="(l,i) in ledger.filter(x=>x.ts_code===s.row.ts_code)" :key="i" class="exp-led">
|
||||
<span class="muted mono">{{ (l.decided_at||'').slice(5,16) }}</span>
|
||||
{{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }}<span v-if="l.reason" class="muted"> — {{ l.reason }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="股票" width="150">
|
||||
<template #default="s"><b>{{ nm(s.row.ts_code) }}</b><br><span class="muted mono">{{ s.row.ts_code }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="现价 / 成本" width="120">
|
||||
<template #default="s">{{ s.row.price }}<span v-if="!s.row.price_ok" class="muted"> 估</span><br><span class="muted">{{ s.row.avg_cost||'—' }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="浮动盈亏" width="110">
|
||||
<template #default="s">
|
||||
<span v-if="s.row.price_ok && s.row.avg_cost" :class="(s.row.price/s.row.avg_cost-1)>=0?'clr-up':'clr-down'">{{ pct(s.row.price/s.row.avg_cost-1) }}</span>
|
||||
<span v-else class="muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="市值 / 占比" width="130">
|
||||
<template #default="s">{{ money(s.row.market_value) }}<br><span class="muted">{{ pct(s.row.pct_of_scale) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="安全垫" width="120">
|
||||
<template #default="s"><el-tag size="small" effect="dark" :type="cuTag(s.row.cushion_state)">{{ tx('cushion', s.row.cushion_state) }}</el-tag>
|
||||
<div class="muted">{{ pct(s.row.cushion_pct) }}<span v-if="s.row.neg_cushion_days>0"> · 连负{{ s.row.neg_cushion_days }}日</span></div></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="120">
|
||||
<template #default="s">{{ tx('posStatus', s.row.status) }}
|
||||
<div v-if="s.row.frozen_reason && s.row.frozen_reason!=='NONE'" style="color:var(--warn)">{{ tx('frozen', s.row.frozen_reason) }}</div></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下一步" min-width="150"><template #default="s"><span class="muted">{{ nextStep(s.row) }}</span></template></el-table-column>
|
||||
<el-table-column label="操作" width="220">
|
||||
<template #default="s">
|
||||
<el-button size="small" @click="actReduceStock(s.row)">减仓</el-button>
|
||||
<el-button size="small" type="danger" @click="actExitStock(s.row)">清仓</el-button>
|
||||
<el-dropdown style="margin-left:6px" @command="c=>rowMore(c,s.row)">
|
||||
<el-button size="small">更多 ▾</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="stop">设止损价</el-dropdown-item>
|
||||
<el-dropdown-item command="target">设目标价</el-dropdown-item>
|
||||
<el-dropdown-item command="freeze">{{ (s.row.frozen_reason && s.row.frozen_reason!=='NONE') ? '解冻' : '冻结(禁增持)' }}</el-dropdown-item>
|
||||
<el-dropdown-item command="black">加入黑名单</el-dropdown-item>
|
||||
<el-dropdown-item command="strategy" divided>挂交易方案(做T/网格/跟踪止盈)</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 4.5) 我的策略 + 操作日志 -->
|
||||
<div class="panel tblk">
|
||||
<h3>我的策略 · {{ strategies.length }} 个
|
||||
<el-tag size="small" :type="stratEnabled?'primary':'info'" effect="dark" style="margin-left:8px">
|
||||
{{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }}</el-tag>
|
||||
<el-checkbox v-model="showAllStrategies" @change="loadStrategies" size="small" style="margin-left:12px;font-weight:normal">显示已撤下/已完成</el-checkbox>
|
||||
<el-tag v-if="autoInfo" size="small" :type="autoInfo.enabled?'primary':'warning'" effect="dark" style="margin-left:12px">
|
||||
{{ autoInfo.enabled ? '自动挂载已开' : '自动挂载总开关未开' }}</el-tag>
|
||||
<el-button size="small" style="margin-left:8px" :loading="autoScanBusy" @click="autoScanPreview">
|
||||
预演</el-button>
|
||||
<span class="help" data-tip="按当前行情与信号试算本轮自动挂载会做什么。仅计算展示,不执行、不落任何记录。">?</span>
|
||||
</h3>
|
||||
<!-- 自动挂载执行状态 (2026-08-26): 正式执行是 09:40 的调度, 此行回答今天执行与否及结果 -->
|
||||
<div class="muted" v-if="autoInfo" style="margin-bottom:6px">
|
||||
<template v-if="autoInfo.ran_today && autoInfo.last_scan">
|
||||
今日自动挂载已于 {{ (autoInfo.last_scan.at||'').slice(11,16) }} 执行:查
|
||||
{{ autoInfo.last_scan.checked }} 只 · 挂载 {{ ((autoInfo.last_scan.counts||{}).attached)||0 }} ·
|
||||
接力 {{ ((autoInfo.last_scan.counts||{}).handoffs)||0 }} · 停买 {{ ((autoInfo.last_scan.counts||{}).paused)||0 }} ·
|
||||
被挡 {{ ((autoInfo.last_scan.counts||{}).blocked)||0 }} · 跳过 {{ ((autoInfo.last_scan.counts||{}).skipped)||0 }}
|
||||
</template>
|
||||
<template v-else>
|
||||
今日自动挂载未执行(交易日 09:40 定时运行)
|
||||
</template>
|
||||
</div>
|
||||
<el-alert v-if="!stratEnabled" type="info" effect="dark" :closable="false" show-icon style="margin-bottom:8px"
|
||||
title="策略挂了也不会出手:请在「设置 / 运维」把 PMS_STRATEGY_ENABLED 打开;影子还是实盘由 PMS_DISPATCH_MODE 决定。"></el-alert>
|
||||
<!-- 自动挂载试算结果 (2026-08-25): 只判断不落任何东西, 真跑在每个交易日 09:40 的调度位 -->
|
||||
<div v-if="autoScanRes" style="border:1px solid var(--bd,#dcdfe6);border-radius:6px;padding:8px 12px;margin-bottom:8px">
|
||||
<div class="muted" style="margin-bottom:4px">
|
||||
预演结果(未执行)· 查 <b>{{ autoScanRes.checked }}</b> 只持仓
|
||||
</div>
|
||||
<!-- 五阶段视图: 每只持仓票当前处在打法状态机的哪个阶段, 不动的票也说清为什么不动 -->
|
||||
<div v-for="(x,i) in (autoScanRes.stages||[])" :key="'stg'+i" style="margin:2px 0">
|
||||
<el-tag size="small" effect="dark" :type="stageTagType(x.stage)">{{ x.stage }}</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b>
|
||||
<span class="muted"> {{ x.why }}
|
||||
<template v-if="x.heat!=null"> · 热度 {{ Number(x.heat).toFixed(2) }}</template>
|
||||
<template v-if="x.cushion_pct!=null"> · 浮盈 {{ pct(x.cushion_pct) }}</template>
|
||||
<template v-if="x.accum_state"> · 定性「{{ x.accum_state }}」</template>
|
||||
</span>
|
||||
</div>
|
||||
<el-divider v-if="(autoScanRes.stages||[]).length" style="margin:6px 0"></el-divider>
|
||||
<div v-for="(x,i) in (autoScanRes.attached||[])" :key="'aa'+i">
|
||||
<el-tag size="small" type="success" effect="dark">想挂</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> {{ tx('stype', x.type) }} —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.handoffs||[])" :key="'ah'+i">
|
||||
<el-tag size="small" type="success" effect="dark">想换挂</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> 网格换跟踪止盈 —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.paused||[])" :key="'ap'+i">
|
||||
<el-tag size="small" type="warning" effect="dark">想停买入</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.resumed||[])" :key="'ar'+i">
|
||||
<el-tag size="small" type="success" effect="dark">想恢复买入</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b></div>
|
||||
<div v-for="(x,i) in (autoScanRes.blocked||[])" :key="'ab'+i" style="color:var(--warn)">
|
||||
<el-tag size="small" type="warning" effect="dark">被挡</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.skipped||[])" :key="'as'+i" class="muted">
|
||||
· <template v-if="x.ts_code">{{ nm(x.ts_code) }}:</template>{{ x.why }}</div>
|
||||
<div v-for="(e,i) in (autoScanRes.errors||[])" :key="'ae'+i" style="color:#d8574a">✗ {{ e }}</div>
|
||||
<div v-if="(autoScanRes.unknown_states||[]).length" style="color:var(--warn)">
|
||||
{{ autoScanRes.unknown_states.length }} 只票的吸筹定性超出约定词表(已按无标志处理),
|
||||
样本:{{ autoScanRes.unknown_states.slice(0,3).map(u=>u.state).join('、') }}。需与决策系统核对
|
||||
</div>
|
||||
<div class="muted" v-if="!(autoScanRes.attached||[]).length && !(autoScanRes.handoffs||[]).length
|
||||
&& !(autoScanRes.paused||[]).length && !(autoScanRes.resumed||[]).length
|
||||
&& !(autoScanRes.blocked||[]).length">
|
||||
本轮无动作:无符合触发条件的信号
|
||||
</div>
|
||||
</div>
|
||||
<div class="muted" v-if="!strategies.length">尚未挂载交易方案。可在「我的持仓」行内「更多 ▾ → 挂交易方案」创建。</div>
|
||||
<el-table v-else :data="strategiesShown" size="small" border max-height="300" empty-text="没有进行中的策略(勾选『显示已撤下/已完成』看全部)">
|
||||
<el-table-column label="股票" width="150"><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="86"><template #default="s"><el-tag size="small" effect="dark">{{ tx('stype', s.row.type) }}</el-tag></template></el-table-column>
|
||||
<el-table-column label="自主档" width="86"><template #default="s">{{ s.row.autonomy==='auto'?'自动执行':'待我拍板' }}</template></el-table-column>
|
||||
<el-table-column label="实时状态" min-width="230"><template #default="s"><span class="muted">{{ stratStateText(s.row) }}</span>
|
||||
<el-tag v-if="s.row.buy_paused" size="small" type="warning" effect="dark" style="margin-left:6px">买入已暂停</el-tag>
|
||||
<div v-if="s.row.buy_paused" style="color:#9a6a00;font-size:11px">决策系统风控:{{ s.row.buy_paused.reason || '资金异动' }}(卖出/平回不受影响;确认无碍点右侧「恢复买入」)</div>
|
||||
</template></el-table-column>
|
||||
<el-table-column label="状态" width="84"><template #default="s"><el-tag size="small" :type="s.row.status==='ACTIVE'?'primary':'info'">{{ tx('stratStatus', s.row.status) }}</el-tag></template></el-table-column>
|
||||
<el-table-column label="操作" width="300"><template #default="s">
|
||||
<el-button v-if="s.row.status==='ACTIVE'" size="small" @click="setStrategyStatus(s.row.strategy_id,'PAUSED')">暂停</el-button>
|
||||
<el-button v-else-if="s.row.status==='PAUSED'" size="small" type="success" @click="setStrategyStatus(s.row.strategy_id,'ACTIVE')">恢复</el-button>
|
||||
<el-button v-if="s.row.buy_paused" size="small" type="warning" @click="resumeBuy(s.row)">恢复买入</el-button>
|
||||
<el-button v-if="!stratArchivable(s.row)" size="small" type="danger" @click="setStrategyStatus(s.row.strategy_id,'CANCELLED')">撤下</el-button>
|
||||
<el-button v-if="stratArchivable(s.row) && !s.row.archived_at" size="small" @click="archiveRow('strategies', s.row.strategy_id, true)">移除</el-button>
|
||||
<el-button v-if="s.row.archived_at" size="small" type="info" @click="archiveRow('strategies', s.row.strategy_id, false)">恢复显示</el-button>
|
||||
</template></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<h3 style="margin-top:14px;cursor:pointer" @click="showOpLog=!showOpLog">操作日志 · {{ opLog.length }} 条 <span class="muted" style="font-size:12px;font-weight:normal">{{ showOpLog?'▲ 收起':'▼ 展开' }}</span></h3>
|
||||
<template v-if="showOpLog">
|
||||
<div class="muted" style="margin-bottom:6px">每次操作留痕一行;被约束挡下的操作记录原因。</div>
|
||||
<div class="muted" v-if="!opLog.length">还没有操作记录。</div>
|
||||
<div v-for="(o,i) in opLog" :key="i" class="feed-row">
|
||||
<span class="muted mono">{{ (o.at||'').slice(11,16) }}</span>
|
||||
<el-tag size="small" :type="o.result==='OK'?'primary':(o.result==='BLOCKED'?'warning':'info')" style="margin:0 6px">{{ o.result }}</el-tag>
|
||||
<b>{{ o.op }}</b><span v-if="o.ts_code" class="muted"> · {{ nm(o.ts_code) }}</span>
|
||||
<span v-if="o.reason" style="color:var(--warn)"> — {{ o.reason }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div><div class="tcol">
|
||||
<!-- 7) 上游信号 (只读参考) -->
|
||||
<div class="panel tblk">
|
||||
<h3 style="cursor:pointer" @click="showUpstream=!showUpstream">上游信号 <span class="muted" style="font-weight:400">· 只读参考,不进下单逻辑</span> <span class="muted" style="font-size:12px;font-weight:normal">{{ showUpstream?'▲ 收起':'▼ 展开' }}</span></h3>
|
||||
<template v-if="showUpstream">
|
||||
<div class="muted" style="margin:-4px 0 12px" v-if="upstream.at">最近取数 {{ (upstream.at||'').slice(11,19) }}(每次刷新拉一次;源自 mtf / 盘中择时层 / 决策系统)</div>
|
||||
<div class="muted" style="margin:-4px 0 12px" v-if="upstream.at">最近取数 {{ (upstream.at||'').slice(11,19) }} · 来源:决策系统 / 盘中择时</div>
|
||||
|
||||
<div class="sig-filter">
|
||||
<span class="muted" style="font-size:12px">级别筛选</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="help" data-tip="点击级别可切换该级告警的显示与隐藏。">?</span>
|
||||
</div>
|
||||
<!-- 常驻盘口: 固定三对, 位置稳定不重排。空的显示暂无, 不再随数据冒出冒消。 -->
|
||||
<!-- 第一对 (拉高并排): mtf 资金异动 | mtf 实况分 关注/回避榜 —— 两边列表通常长 -->
|
||||
|
|
@ -467,134 +696,7 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
|
|||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 1) 今日一览 + 需要注意 -->
|
||||
<div class="metrics">
|
||||
<div class="m"><div class="k">账户总资产</div><div class="v">{{ money(ov.total_asset) }}</div></div>
|
||||
<div class="m"><div class="k">可用资金<span class="muted" v-if="ov.cash_source!=='ws'"> (估算)</span></div>
|
||||
<div class="v" :class="ov.cash_source==='ws'?'':'muted'">{{ money(ov.cash_source==='ws' ? ov.cash_avail : ov.cash_est) }}</div></div>
|
||||
<div class="m"><div class="k">持仓市值</div><div class="v">{{ money(ov.portfolio_mv) }}</div></div>
|
||||
<div class="m"><div class="k">仓位</div><div class="v">{{ pct(ov.portfolio_pct) }}<span class="muted"> / {{ pct(ov.portfolio_cap) }}</span></div></div>
|
||||
<div class="m"><div class="k">浮动盈亏</div>
|
||||
<div class="v" :class="(ov.float_pnl||0)>=0?'up':'down'">{{ money(ov.float_pnl) }}<span style="font-size:13px"> {{ ov.float_pnl_pct==null?'':pct(ov.float_pnl_pct) }}</span></div></div>
|
||||
<div class="m"><div class="k">持仓数</div><div class="v">{{ ov.names_count }}<span class="muted"> / {{ ov.max_names }}</span></div></div>
|
||||
<div class="m" style="cursor:pointer" @click="scrollTo('t-prop')"><div class="k">等我拍板</div>
|
||||
<div class="v" :class="proposals.length?'up':''">{{ proposals.length }} 条</div></div>
|
||||
<div class="m"><div class="k">自主档位</div><div class="v" style="font-size:15px">{{ tx('autonomy', ov.autonomy) }}</div></div>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span>颜色约定:</span>
|
||||
<span><i class="sw" style="background:var(--up)"></i><b class="clr-up">红=涨/盈</b></span>
|
||||
<span><i class="sw" style="background:var(--down)"></i><b class="clr-down">绿=跌/亏</b></span>
|
||||
<span><i class="sw" style="background:var(--warn)"></i><b style="color:var(--warn)">琥珀=需注意</b></span>
|
||||
<span><i class="sw" style="background:var(--stop)"></i><b style="color:var(--stop)">橙=被拦下</b></span>
|
||||
<span><i class="sw" style="background:var(--accent)"></i><b style="color:var(--accent)">蓝=可操作/正常</b></span>
|
||||
<span class="help" data-tip="红绿只用于价格涨跌和盈亏;系统状态(正常/暂停/过期/否决)改用蓝/琥珀/橙/灰,避免看混。">?</span>
|
||||
</div>
|
||||
|
||||
<div class="panel" v-if="attention.length" style="border-color:#7a5b1e">
|
||||
<h3 style="color:#e6a23c">需要注意</h3>
|
||||
<div v-for="(a,i) in attention" :key="i" class="attn">· {{ a }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 2) 等我拍板 -->
|
||||
<div class="panel tblk" id="t-prop">
|
||||
<h3>等我拍板 · {{ proposals.length }} 条</h3>
|
||||
<div class="muted" v-if="!proposals.length">暂无需要你确认的提议。</div>
|
||||
<div v-for="p in proposals" :key="p.proposal_id" class="tcard">
|
||||
<div class="row" style="justify-content:space-between">
|
||||
<div><b style="font-size:15px">{{ nm(p.ts_code) }}</b> <span class="muted mono">{{ p.ts_code }}</span>
|
||||
<el-tag size="small" effect="dark" type="primary" style="margin-left:8px">{{ tx('action', p.action) }}</el-tag></div>
|
||||
<div class="muted">{{ p.expire_at }} 前有效</div>
|
||||
</div>
|
||||
<div style="margin:6px 0" v-if="p.judge_reason"><span class="muted">决策系统:</span>{{ p.judge_reason }}</div>
|
||||
<div class="muted" style="margin:4px 0">{{ propWhy(p) }}</div>
|
||||
<div class="row" style="margin-top:6px">
|
||||
<span class="muted">约 {{ p.qty }} 股 · 参考价 {{ (p.hard_numbers||{}).price==null ? '—' : (p.hard_numbers||{}).price }}
|
||||
· 约需 {{ money(((p.hard_numbers||{}).price||0)*(p.qty||0)) }}</span>
|
||||
<div class="spacer"></div>
|
||||
<el-button type="success" size="small" @click="decide(p,'ACCEPTED')">采纳</el-button>
|
||||
<el-button type="danger" size="small" @click="decide(p,'DECLINED')">驳回</el-button>
|
||||
</div>
|
||||
<div class="muted" style="font-size:11px;margin-top:4px">采纳=记一笔待执行指令,由择时在窗口内择机下单;驳回=今日不再提这只。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3) 我的持仓 -->
|
||||
<div class="panel tblk" id="t-pos">
|
||||
<h3>我的持仓 · {{ heldPositions.length }} 只</h3>
|
||||
<el-table :data="heldPositions" size="small" border max-height="460" @expand-change="onPosExpand">
|
||||
<el-table-column type="expand">
|
||||
<template #default="s">
|
||||
<div class="pos-exp">
|
||||
<div>
|
||||
<div class="exp-h">持仓批次</div>
|
||||
<el-table v-if="lotsOf===s.row.ts_code && lots.length" :data="lots" size="small">
|
||||
<el-table-column label="批次" min-width="84"><template #default="l">{{ tx('lot', l.row.lot_type) }}</template></el-table-column>
|
||||
<el-table-column prop="qty" label="剩余" width="72" align="right"></el-table-column>
|
||||
<el-table-column prop="open_price" label="开仓价" width="80" align="right"></el-table-column>
|
||||
<el-table-column prop="open_date" label="开仓日" width="104"></el-table-column>
|
||||
<el-table-column prop="realized_pnl" label="已实现" width="84" align="right"></el-table-column>
|
||||
</el-table>
|
||||
<div class="muted" v-else-if="lotsOf===s.row.ts_code" style="padding:4px 0">无持仓批次</div>
|
||||
<div class="muted" v-else style="padding:4px 0">载入中…</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="exp-h">该股账本</div>
|
||||
<div class="muted" v-if="!ledger.filter(x=>x.ts_code===s.row.ts_code).length" style="padding:4px 0">今日暂无记录</div>
|
||||
<div v-for="(l,i) in ledger.filter(x=>x.ts_code===s.row.ts_code)" :key="i" class="exp-led">
|
||||
<span class="muted mono">{{ (l.decided_at||'').slice(5,16) }}</span>
|
||||
{{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }}<span v-if="l.reason" class="muted"> — {{ l.reason }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="股票" width="150">
|
||||
<template #default="s"><b>{{ nm(s.row.ts_code) }}</b><br><span class="muted mono">{{ s.row.ts_code }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="现价 / 成本" width="120">
|
||||
<template #default="s">{{ s.row.price }}<span v-if="!s.row.price_ok" class="muted"> 估</span><br><span class="muted">{{ s.row.avg_cost||'—' }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="浮动盈亏" width="110">
|
||||
<template #default="s">
|
||||
<span v-if="s.row.price_ok && s.row.avg_cost" :class="(s.row.price/s.row.avg_cost-1)>=0?'clr-up':'clr-down'">{{ pct(s.row.price/s.row.avg_cost-1) }}</span>
|
||||
<span v-else class="muted">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="市值 / 占比" width="130">
|
||||
<template #default="s">{{ money(s.row.market_value) }}<br><span class="muted">{{ pct(s.row.pct_of_scale) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="安全垫" width="120">
|
||||
<template #default="s"><el-tag size="small" effect="dark" :type="cuTag(s.row.cushion_state)">{{ tx('cushion', s.row.cushion_state) }}</el-tag>
|
||||
<div class="muted">{{ pct(s.row.cushion_pct) }}<span v-if="s.row.neg_cushion_days>0"> · 连负{{ s.row.neg_cushion_days }}日</span></div></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="120">
|
||||
<template #default="s">{{ tx('posStatus', s.row.status) }}
|
||||
<div v-if="s.row.frozen_reason && s.row.frozen_reason!=='NONE'" style="color:var(--warn)">{{ tx('frozen', s.row.frozen_reason) }}</div></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下一步" min-width="150"><template #default="s"><span class="muted">{{ nextStep(s.row) }}</span></template></el-table-column>
|
||||
<el-table-column label="操作" width="220">
|
||||
<template #default="s">
|
||||
<el-button size="small" @click="actReduceStock(s.row)">减仓</el-button>
|
||||
<el-button size="small" type="danger" @click="actExitStock(s.row)">清仓</el-button>
|
||||
<el-dropdown style="margin-left:6px" @command="c=>rowMore(c,s.row)">
|
||||
<el-button size="small">更多 ▾</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="stop">设止损价</el-dropdown-item>
|
||||
<el-dropdown-item command="target">设目标价</el-dropdown-item>
|
||||
<el-dropdown-item command="freeze">{{ (s.row.frozen_reason && s.row.frozen_reason!=='NONE') ? '解冻' : '冻结(禁增持)' }}</el-dropdown-item>
|
||||
<el-dropdown-item command="black">加入黑名单</el-dropdown-item>
|
||||
<el-dropdown-item command="strategy" divided>挂交易方案(做T/网格/跟踪止盈)</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div></div>
|
||||
|
||||
<!-- 4) 今日在办与动向 -->
|
||||
<div class="panel tblk">
|
||||
|
|
@ -648,110 +750,6 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
|
|||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 4.5) 我的策略 + 操作日志 -->
|
||||
<div class="panel tblk">
|
||||
<h3>我的策略 · {{ strategies.length }} 个
|
||||
<el-tag size="small" :type="stratEnabled?'primary':'info'" effect="dark" style="margin-left:8px">
|
||||
{{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }}</el-tag>
|
||||
<el-checkbox v-model="showAllStrategies" @change="loadStrategies" size="small" style="margin-left:12px;font-weight:normal">显示已撤下/已完成</el-checkbox>
|
||||
<el-tag v-if="autoInfo" size="small" :type="autoInfo.enabled?'primary':'warning'" effect="dark" style="margin-left:12px">
|
||||
{{ autoInfo.enabled ? '自动挂载已开' : '自动挂载总开关未开' }}</el-tag>
|
||||
<el-button size="small" style="margin-left:8px" :loading="autoScanBusy" @click="autoScanPreview">
|
||||
预演 · 现在系统想做什么</el-button>
|
||||
</h3>
|
||||
<!-- 自动挂载仪表 (2026-08-26): 正式跑与预演分清 —— 正式跑是 09:40 的调度, 这里回答它今天
|
||||
跑没跑、做了什么; 旁边按钮只是预演镜, 随便点, 不动任何东西。 -->
|
||||
<div class="muted" v-if="autoInfo" style="margin-bottom:6px">
|
||||
<template v-if="autoInfo.ran_today && autoInfo.last_scan">
|
||||
今天的正式一跳已在 {{ (autoInfo.last_scan.at||'').slice(11,16) }} 跑过:查
|
||||
{{ autoInfo.last_scan.checked }} 只,挂载 {{ ((autoInfo.last_scan.counts||{}).attached)||0 }}、
|
||||
接力 {{ ((autoInfo.last_scan.counts||{}).handoffs)||0 }}、停买入 {{ ((autoInfo.last_scan.counts||{}).paused)||0 }}、
|
||||
被挡 {{ ((autoInfo.last_scan.counts||{}).blocked)||0 }}、跳过 {{ ((autoInfo.last_scan.counts||{}).skipped)||0 }}。
|
||||
</template>
|
||||
<template v-else>
|
||||
今天的正式一跳还没跑(每个交易日 09:40 由调度自动执行,跑完这里会显示结果)。
|
||||
</template>
|
||||
「预演」按钮只是看一眼:按此刻的行情和信号算一遍会做什么,不挂载、不留痕,随便点。
|
||||
</div>
|
||||
<el-alert v-if="!stratEnabled" type="info" effect="dark" :closable="false" show-icon style="margin-bottom:8px"
|
||||
title="策略挂了也不会出手:请在「设置 / 运维」把 PMS_STRATEGY_ENABLED 打开;影子还是实盘由 PMS_DISPATCH_MODE 决定。"></el-alert>
|
||||
<!-- 自动挂载试算结果 (2026-08-25): 只判断不落任何东西, 真跑在每个交易日 09:40 的调度位 -->
|
||||
<div v-if="autoScanRes" style="border:1px solid var(--bd,#dcdfe6);border-radius:6px;padding:8px 12px;margin-bottom:8px">
|
||||
<div class="muted" style="margin-bottom:4px">
|
||||
以下为预演结果:按此刻的行情和信号,系统会做什么。只是看一眼,什么都没动。
|
||||
本轮查了 <b>{{ autoScanRes.checked }}</b> 只持仓票。
|
||||
</div>
|
||||
<!-- 五阶段视图: 每只持仓票当前处在打法状态机的哪个阶段, 不动的票也说清为什么不动 -->
|
||||
<div v-for="(x,i) in (autoScanRes.stages||[])" :key="'stg'+i" style="margin:2px 0">
|
||||
<el-tag size="small" effect="dark" :type="stageTagType(x.stage)">{{ x.stage }}</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b>
|
||||
<span class="muted"> {{ x.why }}
|
||||
<template v-if="x.heat!=null"> · 热度 {{ Number(x.heat).toFixed(2) }}</template>
|
||||
<template v-if="x.cushion_pct!=null"> · 浮盈 {{ pct(x.cushion_pct) }}</template>
|
||||
<template v-if="x.accum_state"> · 定性「{{ x.accum_state }}」</template>
|
||||
</span>
|
||||
</div>
|
||||
<el-divider v-if="(autoScanRes.stages||[]).length" style="margin:6px 0"></el-divider>
|
||||
<div v-for="(x,i) in (autoScanRes.attached||[])" :key="'aa'+i">
|
||||
<el-tag size="small" type="success" effect="dark">想挂</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> {{ tx('stype', x.type) }} —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.handoffs||[])" :key="'ah'+i">
|
||||
<el-tag size="small" type="success" effect="dark">想换挂</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> 网格换跟踪止盈 —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.paused||[])" :key="'ap'+i">
|
||||
<el-tag size="small" type="warning" effect="dark">想停买入</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.resumed||[])" :key="'ar'+i">
|
||||
<el-tag size="small" type="success" effect="dark">想恢复买入</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b></div>
|
||||
<div v-for="(x,i) in (autoScanRes.blocked||[])" :key="'ab'+i" style="color:var(--warn)">
|
||||
<el-tag size="small" type="warning" effect="dark">被挡</el-tag>
|
||||
<b> {{ nm(x.ts_code) }}</b> —— {{ x.why }}</div>
|
||||
<div v-for="(x,i) in (autoScanRes.skipped||[])" :key="'as'+i" class="muted">
|
||||
· <template v-if="x.ts_code">{{ nm(x.ts_code) }}:</template>{{ x.why }}</div>
|
||||
<div v-for="(e,i) in (autoScanRes.errors||[])" :key="'ae'+i" style="color:#d8574a">✗ {{ e }}</div>
|
||||
<div v-if="(autoScanRes.unknown_states||[]).length" style="color:var(--warn)">
|
||||
有 {{ autoScanRes.unknown_states.length }} 只票的吸筹说法不在约定词表里(按无标志处理),
|
||||
样本:{{ autoScanRes.unknown_states.slice(0,3).map(u=>u.state).join('、') }}——需与决策系统核对。
|
||||
</div>
|
||||
<div class="muted" v-if="!(autoScanRes.attached||[]).length && !(autoScanRes.handoffs||[]).length
|
||||
&& !(autoScanRes.paused||[]).length && !(autoScanRes.resumed||[]).length
|
||||
&& !(autoScanRes.blocked||[]).length">
|
||||
今天没有想动的:持仓里暂时没有够格的信号,这是正常的克制。
|
||||
</div>
|
||||
</div>
|
||||
<div class="muted" v-if="!strategies.length">还没有挂任何交易方案。到「我的持仓」某行「更多 ▾ → 挂交易方案」给它挂一个。</div>
|
||||
<el-table v-else :data="strategiesShown" size="small" border max-height="300" empty-text="没有进行中的策略(勾选『显示已撤下/已完成』看全部)">
|
||||
<el-table-column label="股票" width="150"><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="86"><template #default="s"><el-tag size="small" effect="dark">{{ tx('stype', s.row.type) }}</el-tag></template></el-table-column>
|
||||
<el-table-column label="自主档" width="86"><template #default="s">{{ s.row.autonomy==='auto'?'自动执行':'待我拍板' }}</template></el-table-column>
|
||||
<el-table-column label="实时状态" min-width="230"><template #default="s"><span class="muted">{{ stratStateText(s.row) }}</span>
|
||||
<el-tag v-if="s.row.buy_paused" size="small" type="warning" effect="dark" style="margin-left:6px">买入已暂停</el-tag>
|
||||
<div v-if="s.row.buy_paused" style="color:#9a6a00;font-size:11px">决策系统风控:{{ s.row.buy_paused.reason || '资金异动' }}(卖出/平回不受影响;确认无碍点右侧「恢复买入」)</div>
|
||||
</template></el-table-column>
|
||||
<el-table-column label="状态" width="84"><template #default="s"><el-tag size="small" :type="s.row.status==='ACTIVE'?'primary':'info'">{{ tx('stratStatus', s.row.status) }}</el-tag></template></el-table-column>
|
||||
<el-table-column label="操作" width="300"><template #default="s">
|
||||
<el-button v-if="s.row.status==='ACTIVE'" size="small" @click="setStrategyStatus(s.row.strategy_id,'PAUSED')">暂停</el-button>
|
||||
<el-button v-else-if="s.row.status==='PAUSED'" size="small" type="success" @click="setStrategyStatus(s.row.strategy_id,'ACTIVE')">恢复</el-button>
|
||||
<el-button v-if="s.row.buy_paused" size="small" type="warning" @click="resumeBuy(s.row)">恢复买入</el-button>
|
||||
<el-button v-if="!stratArchivable(s.row)" size="small" type="danger" @click="setStrategyStatus(s.row.strategy_id,'CANCELLED')">撤下</el-button>
|
||||
<el-button v-if="stratArchivable(s.row) && !s.row.archived_at" size="small" @click="archiveRow('strategies', s.row.strategy_id, true)">移除</el-button>
|
||||
<el-button v-if="s.row.archived_at" size="small" type="info" @click="archiveRow('strategies', s.row.strategy_id, false)">恢复显示</el-button>
|
||||
</template></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<h3 style="margin-top:14px;cursor:pointer" @click="showOpLog=!showOpLog">操作日志 · {{ opLog.length }} 条 <span class="muted" style="font-size:12px;font-weight:normal">{{ showOpLog?'▲ 收起':'▼ 展开' }}</span></h3>
|
||||
<template v-if="showOpLog">
|
||||
<div class="muted" style="margin-bottom:6px">每一次页面写操作都留一行;被仓位 / 盈亏 / T+1 可卖 / 单股上限挡下的,连原因一起记,不静默。</div>
|
||||
<div class="muted" v-if="!opLog.length">还没有操作记录。</div>
|
||||
<div v-for="(o,i) in opLog" :key="i" class="feed-row">
|
||||
<span class="muted mono">{{ (o.at||'').slice(11,16) }}</span>
|
||||
<el-tag size="small" :type="o.result==='OK'?'primary':(o.result==='BLOCKED'?'warning':'info')" style="margin:0 6px">{{ o.result }}</el-tag>
|
||||
<b>{{ o.op }}</b><span v-if="o.ts_code" class="muted"> · {{ nm(o.ts_code) }}</span>
|
||||
<span v-if="o.reason" style="color:var(--warn)"> — {{ o.reason }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 挂交易方案 对话框 (非盲填: 现价/持仓/可卖/浮盈都摆出来) -->
|
||||
<el-dialog v-model="stratDlg.visible" :title="'挂交易方案 · ' + nm(stratDlg.ts_code)" width="580px">
|
||||
|
|
@ -1650,7 +1648,7 @@ createApp({
|
|||
const lastRefresh = ref('');
|
||||
const autoRefresh = ref(true);
|
||||
const upstream = ref({ sources: {} });
|
||||
const showUpstream = ref(false); // 默认折叠, 点标题展开
|
||||
const showUpstream = ref(true); // 双栏后信号在右栏常驻显示, 点标题可折叠 (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 —— 普通刷新保留, 关标签页/新开标签=回默认。默认关 普通/提示。
|
||||
|
|
|
|||
|
|
@ -643,7 +643,7 @@ def _():
|
|||
out2 = _out()
|
||||
adv._tend_existing(auto_trail, _pos(price=10.6), {"cls": adv.CLS_CLEAR}, True, 0.9,
|
||||
_prm(), {}, set(), TODAY, False, out2, fake_svc)
|
||||
assert any("本轮无事" in s["why"] for s in out2["skipped"]), out2["skipped"]
|
||||
assert any("本轮无需变更" in s["why"] for s in out2["skipped"]), out2["skipped"]
|
||||
# 半途而废: 撤成挂败 → errors 里有「人工处理」, 留痕 HANDOFF/REJECT
|
||||
orig_led, orig_upd = pms_repo.insert_ledger, pms_repo.update_strategy
|
||||
pms_repo.insert_ledger = lambda **kw: rec.ledger.append(kw) or 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue