修改页面布局样式
This commit is contained in:
parent
0fb958ce51
commit
0ff719ad0b
|
|
@ -209,6 +209,58 @@ def _scan_open(view, params, stock_params, skip, mkt, out) -> list:
|
||||||
return res["candidates"]
|
return res["candidates"]
|
||||||
|
|
||||||
|
|
||||||
|
def disposition_snapshot(now=None) -> dict:
|
||||||
|
"""候选池处置快照 (只读, 无副作用): 候选池里每只票今天为什么下单 / 没下单。
|
||||||
|
|
||||||
|
页面「系统在盯的候选」原来只铺上游榜单, 看不出每只票的去向。这里补上去向与原因:
|
||||||
|
名额满 / 可投金额不足 / 超上限 / 不足一手 / 在途 / 已持有 / 今日已拒 —— 这些原因每分钟的
|
||||||
|
scan_and_route 都算了, 但算完即弃 (评审账本只留规则闸/研判闸的驳回, 这一层查不到)。
|
||||||
|
|
||||||
|
实现上**直接复用** `_scan_open`: 把它写 out / mkt 的两个收集器换成丢弃用的临时容器,
|
||||||
|
一个字都不改扫描逻辑, 口径与实盘扫描逐字一致 (不另写一份, 免得日后分叉)。_scan_open 内部
|
||||||
|
只读库与行情、不落任何表, 所以这样调用是安全的。
|
||||||
|
「已下单 / 已生成提议」交给前端用它已在手的 instructions / proposals 按股票对齐, 这里不重复查。
|
||||||
|
"""
|
||||||
|
now = now or datetime.now()
|
||||||
|
res = {"ok": True, "ready": True, "at": now.isoformat(timespec="seconds"),
|
||||||
|
"by_code": {}, "notes": [],
|
||||||
|
"autonomy": param_store.get("PMS_AUTONOMY", AUTONOMY_PROPOSE),
|
||||||
|
"open_autonomy": param_store.get("PMS_OPEN_AUTONOMY", AUTONOMY_FULL)}
|
||||||
|
if res["autonomy"] == AUTONOMY_OFF:
|
||||||
|
res["notes"].append("自主档位 off —— 本轮不扫描候选池 (off 是总闸)")
|
||||||
|
return res
|
||||||
|
if param_store.get_bool("PMS_GLOBAL_EXEC_HALT", False):
|
||||||
|
res["notes"].append("全局暂停执行 (休假模式) —— 本轮不扫描候选池")
|
||||||
|
return res
|
||||||
|
if res["open_autonomy"] == AUTONOMY_OFF:
|
||||||
|
res["notes"].append("新建仓档位 off —— 不扫描候选池")
|
||||||
|
return res
|
||||||
|
try:
|
||||||
|
view = portfolio.positions_view()
|
||||||
|
params = _scan_params(view)
|
||||||
|
stock_params = command_service.effective_stock_params()
|
||||||
|
# 与实盘扫描同一份 skip: 在途 / 今日已被规则闸拒 / 今日已被研判闸驳回的新建仓
|
||||||
|
skip = {**_judge_rejected_open_keys(), **_rejected_today_keys(), **_inflight_keys()}
|
||||||
|
sink = {"skipped": []} # 丢弃用: _scan_open 只往里 append/extend, 不读它
|
||||||
|
would = _scan_open(view, params, stock_params, skip, {}, sink)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("候选处置快照失败")
|
||||||
|
return {"ok": False, "ready": False, "error": f"{type(e).__name__}: {e}",
|
||||||
|
"by_code": {}, "notes": []}
|
||||||
|
for c in would:
|
||||||
|
res["by_code"][c["ts_code"]] = {
|
||||||
|
"disp": "would", "why": "名额与资金都够, 本轮将建底仓 (下一跳落单)"}
|
||||||
|
for s in sink["skipped"]:
|
||||||
|
code = s.get("ts_code")
|
||||||
|
if not code or code == "*": # 池级原因 (名额满/资金为零/候选池空…) 挂到 notes
|
||||||
|
if s.get("why"):
|
||||||
|
res["notes"].append(s["why"])
|
||||||
|
else: # 单票原因; 不覆盖已判 would 的
|
||||||
|
res["by_code"].setdefault(
|
||||||
|
code, {"disp": "deny", "why": s.get("why") or "未产出候选"})
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
def _route_one(c, view, params, stock_params, brake_active, now, dry_run, out,
|
def _route_one(c, view, params, stock_params, brake_active, now, dry_run, out,
|
||||||
*, deadline=None):
|
*, deadline=None):
|
||||||
code, action, side = c["ts_code"], c["action"], c["side"]
|
code, action, side = c["ts_code"], c["action"], c["side"]
|
||||||
|
|
|
||||||
|
|
@ -486,6 +486,18 @@ def api_clear_resync():
|
||||||
|
|
||||||
|
|
||||||
# ================================================================ 上游选股计划
|
# ================================================================ 上游选股计划
|
||||||
|
@app.get("/api/open-scan")
|
||||||
|
def api_open_scan():
|
||||||
|
"""候选池处置快照 (只读): 每只候选今天为什么下单 / 没下单。
|
||||||
|
|
||||||
|
复用每分钟那条自主扫描的 scan_open 口径, 但止步于规则闸之前、不送研判、不落任何表 ——
|
||||||
|
补上「名额/资金/上限/不足一手/在途/已持有」这些算完即弃、评审账本里查不到的原因。
|
||||||
|
「已下单/已生成提议」由前端拿它已在手的 instructions/proposals 按股票对齐, 这里不重复查。
|
||||||
|
"""
|
||||||
|
from app.services import proposal_service
|
||||||
|
return ok(proposal_service.disposition_snapshot)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/upstream/plan")
|
@app.get("/api/upstream/plan")
|
||||||
def api_upstream_plan(limit: int = Query(30), date: str = Query(None),
|
def api_upstream_plan(limit: int = Query(30), date: str = Query(None),
|
||||||
bucket: str = Query("main")):
|
bucket: str = Query("main")):
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,128 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN" class="dark">
|
<html lang="zh-CN" data-theme="light">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>PMS 持仓管理系统</title>
|
<title>PMS 持仓管理系统</title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"/>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/element-plus/theme-chalk/dark/css-vars.css"/>
|
|
||||||
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||||||
<script src="https://unpkg.com/element-plus"></script>
|
<script src="https://unpkg.com/element-plus"></script>
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body { margin:0; background:#0f0f0f; color:#ccc; font-family:'Inter',system-ui,sans-serif; }
|
:root, html[data-theme=light]{
|
||||||
.app { padding:12px 18px 32px; }
|
--plane:#f4f5f2; --surface:#ffffff; --surface-2:#fafaf8; --ink:#141412; --ink-2:#54534f; --muted:#8a8882;
|
||||||
.hd { display:flex; align-items:center; gap:14px; flex-wrap:wrap;
|
--hair:#e7e6df; --ring:rgba(17,17,16,.10); --accent:#2a78d6; --accent-weak:#ecf3fd;
|
||||||
padding:10px 14px; background:#1a1a1a; border:1px solid #333; border-radius:8px; }
|
--up:#d5342f; --up-weak:#fbeceb; --down:#158a4c; --down-weak:#e7f4ec;
|
||||||
.hd h1 { font-size:17px; margin:0; color:#eee; font-weight:600; letter-spacing:.5px; }
|
--warn:#9a6a00; --warn-weak:#fbf1d6; --stop:#b4552b; --stop-weak:#fbeadf;
|
||||||
.hd .ver { color:#666; font-size:12px; }
|
--shadow:0 1px 2px rgba(17,17,16,.04),0 2px 8px rgba(17,17,16,.045);
|
||||||
.spacer { flex:1; }
|
}
|
||||||
.metrics { display:flex; gap:10px; flex-wrap:wrap; margin:12px 0; }
|
[v-cloak]{display:none;}
|
||||||
.m { background:#1a1a1a; border:1px solid #333; border-radius:8px; padding:10px 14px; min-width:118px; }
|
body{margin:0;background:var(--plane);color:var(--ink);
|
||||||
.m .k { color:#888; font-size:12px; }
|
font-family:system-ui,-apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;}
|
||||||
.m .v { color:#eee; font-size:18px; font-weight:600; margin-top:3px; }
|
.app{max-width:1280px;margin:0 auto;padding:0 20px 44px;}
|
||||||
.m .v.up { color:#f56c6c; } .m .v.down { color:#67c23a; }
|
.mono{font-family:ui-monospace,Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;}
|
||||||
.panel { background:#1a1a1a; border:1px solid #333; border-radius:8px; padding:14px; margin-bottom:14px; }
|
.muted{color:var(--muted);font-size:12.5px;}
|
||||||
.panel h3 { margin:0 0 10px; font-size:14px; color:#409EFF; font-weight:600; }
|
.nowrap{white-space:nowrap;}
|
||||||
.muted { color:#777; font-size:12px; }
|
.spacer{flex:1;}
|
||||||
.row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
|
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;}
|
||||||
.banner { margin:10px 0; }
|
.clr-up{color:var(--up);} .clr-down{color:var(--down);}
|
||||||
.el-table { background:transparent !important; font-size:13px; }
|
/* 顶栏 */
|
||||||
.tier { font-size:12px; color:#909399; }
|
.hd{position:sticky;top:0;z-index:30;display:flex;align-items:center;gap:9px;flex-wrap:wrap;
|
||||||
.mono { font-family:ui-monospace,Menlo,Consolas,monospace; }
|
margin:0 -20px 6px;padding:10px 20px;background:rgba(244,245,242,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--hair);}
|
||||||
.nowrap { white-space:nowrap; }
|
.hd h1{font-size:15px;margin:0;font-weight:680;letter-spacing:.2px;}
|
||||||
pre.json { background:#111; border:1px solid #333; border-radius:6px; padding:10px;
|
.hd .ver{color:var(--muted);font-size:12px;font-weight:400;margin-left:6px;}
|
||||||
max-height:420px; overflow:auto; font-size:12px; color:#bbb; }
|
.seg{display:inline-flex;border:1px solid var(--hair);border-radius:8px;overflow:hidden;background:var(--surface);}
|
||||||
.tcard{background:#161616;border:1px solid #333;border-radius:8px;padding:10px 12px;margin-bottom:10px;}
|
.seg button{border:0;background:transparent;color:var(--ink-2);padding:5px 12px;font-size:13px;cursor:pointer;}
|
||||||
.clr-up{color:#f56c6c;} .clr-down{color:#67c23a;}
|
.seg button.on{background:var(--accent);color:#fff;}
|
||||||
.attn{color:#e6a23c;padding:3px 0;}
|
.tbtn{border:1px solid var(--hair);background:var(--surface);color:var(--ink);border-radius:8px;padding:6px 12px;font-size:13px;cursor:pointer;font-weight:520;}
|
||||||
.tblk h3{margin:0 0 10px;font-size:14px;color:#409EFF;font-weight:600;}
|
.tbtn:hover{border-color:var(--accent);color:var(--accent);}
|
||||||
.op-row{display:flex;align-items:flex-start;gap:12px;padding:6px 0;border-bottom:1px solid #262626;}
|
.tbtn.pri{background:var(--accent);border-color:var(--accent);color:#fff;}
|
||||||
.op-row:last-child{border-bottom:none;}
|
.tbtn.pri:hover{color:#fff;}
|
||||||
.op-btn{flex:none;width:150px;}
|
.tbtn.sm{padding:3px 10px;font-size:12.5px;}
|
||||||
.op-btn .el-button{width:100%;}
|
/* 状态胶囊(系统状态:不用红绿) */
|
||||||
.op-row .d{color:#999;font-size:12px;line-height:1.5;padding-top:3px;}
|
.chip{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:560;padding:3px 9px;border-radius:999px;white-space:nowrap;}
|
||||||
.set-card{border:1px solid #333;border-radius:6px;padding:10px 12px;margin-bottom:10px;}
|
.chip .dot{width:6px;height:6px;border-radius:50%;flex:none;}
|
||||||
.set-sum{color:#ddd;font-size:13px;margin-bottom:8px;line-height:1.6;}
|
.chip.ok{background:var(--accent-weak);color:var(--accent);} .chip.ok .dot{background:var(--accent);}
|
||||||
.set-fields{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;color:#999;font-size:12px;}
|
.chip.warn{background:var(--warn-weak);color:var(--warn);} .chip.warn .dot{background:var(--warn);}
|
||||||
|
.chip.idle{background:rgba(138,136,130,.15);color:var(--ink-2);} .chip.idle .dot{background:var(--muted);}
|
||||||
|
.chip.stop{background:var(--stop-weak);color:var(--stop);} .chip.stop .dot{background:var(--stop);}
|
||||||
|
.help{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;
|
||||||
|
border:1px solid var(--muted);color:var(--muted);font-size:10px;cursor:help;position:relative;font-weight:600;margin-left:3px;}
|
||||||
|
.help:hover::after{content:attr(data-tip);position:absolute;left:0;top:150%;width:250px;background:var(--ink);color:#fff;
|
||||||
|
font-size:12px;font-weight:400;line-height:1.5;padding:8px 10px;border-radius:8px;z-index:50;box-shadow:0 6px 20px rgba(0,0,0,.22);}
|
||||||
|
/* KPI 焦点行 */
|
||||||
|
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:12px;margin:16px 0;}
|
||||||
|
.m{background:var(--surface);border:1px solid var(--hair);border-radius:12px;padding:12px 15px;box-shadow:var(--shadow);}
|
||||||
|
.m .k{color:var(--muted);font-size:12px;}
|
||||||
|
.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);}
|
||||||
|
/* 颜色约定图例 */
|
||||||
|
.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;}
|
||||||
|
/* 卡片/面板 */
|
||||||
|
.panel{background:var(--surface);border:1px solid var(--hair);border-radius:14px;padding:16px 18px;margin-bottom:16px;box-shadow:var(--shadow);}
|
||||||
|
.panel h3,.tblk h3{margin:0 0 10px;font-size:15px;color:var(--ink);font-weight:660;}
|
||||||
|
.sub2{color:var(--muted);font-size:12.5px;margin:-4px 0 12px;}
|
||||||
|
.banner{margin:10px 0;}
|
||||||
|
.attn{color:var(--warn);padding:4px 0;}
|
||||||
|
.tcard{background:var(--surface-2);border:1px solid var(--hair);border-radius:11px;padding:12px 14px;margin-bottom:10px;}
|
||||||
|
.feed-row{padding:5px 0;border-bottom:1px solid var(--hair);font-size:13px;}
|
||||||
|
.feed-row:last-child{border-bottom:none;}
|
||||||
|
.tag{display:inline-block;font-size:11.5px;font-weight:560;padding:2px 8px;border-radius:6px;background:rgba(138,136,130,.14);color:var(--ink-2);}
|
||||||
|
.tier{font-size:12px;color:var(--muted);}
|
||||||
|
/* 处置胶囊(候选表) */
|
||||||
|
.disp{display:inline-flex;align-items:center;gap:3px;font-size:12px;font-weight:600;padding:3px 9px;border-radius:7px;}
|
||||||
|
.disp.done{background:var(--accent-weak);color:var(--accent);}
|
||||||
|
.disp.queue{background:var(--warn-weak);color:var(--warn);}
|
||||||
|
.disp.deny{background:var(--stop-weak);color:var(--stop);}
|
||||||
|
.disp.would{background:var(--surface);color:var(--accent);border:1px solid var(--accent);}
|
||||||
|
.disp.wait{background:rgba(138,136,130,.14);color:var(--ink-2);}
|
||||||
|
.why{color:var(--ink-2);font-size:12.5px;margin-top:3px;line-height:1.45;}
|
||||||
|
.pool-note{margin:0 0 12px;padding:9px 12px;background:var(--surface-2);border:1px solid var(--hair);border-radius:9px;color:var(--ink-2);font-size:12.5px;}
|
||||||
|
.tabn{color:var(--muted);font-weight:600;font-size:12px;margin-left:3px;}
|
||||||
|
/* 组合操作 / 设置 */
|
||||||
|
.op-row{display:flex;align-items:flex-start;gap:12px;padding:9px 0;border-bottom:1px solid var(--hair);}
|
||||||
|
.op-row:last-child{border-bottom:none;}
|
||||||
|
.op-btn{flex:none;width:150px;} .op-btn .el-button{width:100%;}
|
||||||
|
.op-row .d{color:var(--ink-2);font-size:12.5px;line-height:1.55;padding-top:3px;}
|
||||||
|
.set-card{border:1px solid var(--hair);border-radius:10px;padding:12px 14px;margin-bottom:10px;background:var(--surface-2);}
|
||||||
|
.set-sum{color:var(--ink);font-size:13px;margin-bottom:8px;line-height:1.6;}
|
||||||
|
.set-fields{display:flex;flex-wrap:wrap;gap:10px 16px;align-items:center;color:var(--ink-2);font-size:12px;}
|
||||||
|
pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:8px;padding:10px;max-height:420px;overflow:auto;font-size:12px;color:var(--ink-2);}
|
||||||
|
/* Element Plus 浅色微调 */
|
||||||
|
.el-table{background:transparent!important;font-size:13px;
|
||||||
|
--el-table-border-color:var(--hair);--el-table-header-bg-color:var(--surface-2);
|
||||||
|
--el-table-row-hover-bg-color:var(--surface-2);--el-table-bg-color:transparent;--el-table-tr-bg-color:transparent;}
|
||||||
|
.el-table th.el-table__cell{background:var(--surface-2)!important;color:var(--muted)!important;font-weight:560;}
|
||||||
|
.el-table td.el-table__cell,.el-table th.el-table__cell{padding:10px 0;border-color:var(--hair)!important;}
|
||||||
|
.el-table .cell{color:var(--ink);line-height:1.5;}
|
||||||
|
.el-tabs__item{font-size:14px;color:var(--muted);font-weight:560;}
|
||||||
|
.el-tabs__item.is-active{color:var(--ink);}
|
||||||
|
.el-tabs__active-bar{background:var(--accent);}
|
||||||
|
.el-tabs__nav-wrap::after{background:var(--hair);height:1px;}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app" class="app" v-cloak>
|
<div id="app" class="app" v-cloak>
|
||||||
|
|
||||||
<div class="hd">
|
<div class="hd">
|
||||||
<h1>PMS 持仓管理系统</h1>
|
<h1>PMS 持仓管理<span class="ver">v{{ health.version || '-' }} · {{ health.now || '' }}</span></h1>
|
||||||
<span class="ver">v{{ health.version || '-' }} · {{ health.now || '' }}
|
<span class="chip" :class="health.trade_day?'ok':'idle'"><span class="dot"></span>{{ health.trade_day ? '交易日':'非交易日' }}</span>
|
||||||
<el-tag v-if="health.trade_day" size="small" type="success" effect="dark">交易日</el-tag>
|
<span class="chip" :class="ov.buy_halt?'warn':'ok'"><span class="dot"></span>买入 {{ ov.buy_halt ? '已暂停':'正常' }}</span>
|
||||||
<el-tag v-else size="small" type="info" effect="dark">非交易日</el-tag>
|
<span class="chip" :class="ov.exec_halt?'warn':'ok'"><span class="dot"></span>执行 {{ ov.exec_halt ? '已暂停':'正常' }}</span>
|
||||||
</span>
|
<span class="chip" :class="ov.autonomy==='off'?'warn':'ok'"><span class="dot"></span>自主 {{ tx('autonomy', ov.autonomy) }}<span class="help" data-tip="系统自己出手的程度:全自动=闸门通过就执行;只提议=等你在『等我拍板』确认;暂停=不自动动作。">?</span></span>
|
||||||
<el-button-group style="margin-left:8px">
|
<span class="chip" :class="planStatus.ok===false?'warn':'ok'"><span class="dot"></span>计划 {{ planStatus.ok===false ? '不可用' : (planStatus.date || '-') }}</span>
|
||||||
<el-button size="small" :type="mode==='trader'?'primary':''" @click="mode='trader'">交易员</el-button>
|
<span class="chip" :class="dm.shadow?'idle':'ok'" v-show="mode==='ops'"><span class="dot"></span>下发 {{ dm.mode || '-' }}<span class="help" data-tip="实盘=真发到 QMT 下单;影子=只记录不真下单,用来观察。">?</span></span>
|
||||||
<el-button size="small" :type="mode==='ops'?'primary':''" @click="mode='ops'">运维</el-button>
|
|
||||||
</el-button-group>
|
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<el-tag :type="ov.buy_halt ? 'danger':'info'" effect="dark" size="small">
|
<div class="seg">
|
||||||
买入 {{ ov.buy_halt ? '已暂停':'正常' }}</el-tag>
|
<button :class="{on:mode==='trader'}" @click="mode='trader'">交易员</button>
|
||||||
<el-tag :type="ov.exec_halt ? 'danger':'info'" effect="dark" size="small">
|
<button :class="{on:mode==='ops'}" @click="mode='ops'">运维</button>
|
||||||
执行 {{ ov.exec_halt ? '已暂停':'正常' }}</el-tag>
|
</div>
|
||||||
<el-tag type="warning" effect="dark" size="small">自主档位 {{ tx('autonomy', ov.autonomy) }}</el-tag>
|
<button class="tbtn" @click="openPlan">上游计划</button>
|
||||||
<el-tag :type="dm.shadow ? 'info':'success'" effect="dark" size="small" v-show="mode==='ops'">
|
<button class="tbtn" @click="openReport">日报</button>
|
||||||
下发 {{ dm.mode || '-' }}</el-tag>
|
<button class="tbtn" v-show="mode==='ops'" @click="opsDrawer=true">运维</button>
|
||||||
<el-tag :type="planStatus.ok===false ? 'danger':'success'" effect="dark" size="small">
|
<button class="tbtn pri" :disabled="loading" @click="loadAll">{{ loading ? '刷新中…' : '刷新' }}</button>
|
||||||
计划 {{ planStatus.ok===false ? '不可用' : (planStatus.date || '-') }}</el-tag>
|
|
||||||
<el-button size="small" @click="openPlan">上游计划</el-button>
|
|
||||||
<el-button size="small" @click="openReport">日报</el-button>
|
|
||||||
<el-button size="small" v-show="mode==='ops'" @click="opsDrawer=true">运维</el-button>
|
|
||||||
<el-button size="small" type="primary" :loading="loading" @click="loadAll">刷新</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-alert v-if="err" class="banner" :title="err" type="error" effect="dark" show-icon
|
<el-alert v-if="err" class="banner" :title="err" type="error" effect="dark" show-icon
|
||||||
|
|
@ -113,6 +162,16 @@
|
||||||
<div class="v" :class="proposals.length?'up':''">{{ proposals.length }} 条</div></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 class="m"><div class="k">自主档位</div><div class="v" style="font-size:15px">{{ tx('autonomy', ov.autonomy) }}</div></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">
|
<div class="panel" v-if="attention.length" style="border-color:#7a5b1e">
|
||||||
<h3 style="color:#e6a23c">需要注意</h3>
|
<h3 style="color:#e6a23c">需要注意</h3>
|
||||||
<div v-for="(a,i) in attention" :key="i" class="attn">· {{ a }}</div>
|
<div v-for="(a,i) in attention" :key="i" class="attn">· {{ a }}</div>
|
||||||
|
|
@ -216,19 +275,42 @@
|
||||||
<!-- 4) 今日在办与动向 -->
|
<!-- 4) 今日在办与动向 -->
|
||||||
<div class="panel tblk">
|
<div class="panel tblk">
|
||||||
<h3>今日在办</h3>
|
<h3>今日在办</h3>
|
||||||
<el-table :data="instructions" size="small" border max-height="240" empty-text="今天没有在办的买卖">
|
<div class="sub2">今天下出去的买卖单,按状态分三档:还在跑的、已成交的、已经结束的。</div>
|
||||||
<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-tabs v-model="insTab">
|
||||||
<el-table-column label="动作" width="150"><template #default="s">{{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}</template></el-table-column>
|
<el-tab-pane name="live">
|
||||||
<el-table-column label="数量 / 已成" width="110"><template #default="s">{{ s.row.qty }} / {{ s.row.exec_qty||0 }}</template></el-table-column>
|
<template #label>在办中 <span class="tabn">{{ insLive.length }}</span></template>
|
||||||
<el-table-column prop="limit_price" label="限价" width="90"></el-table-column>
|
<el-table :data="insLive" size="small" max-height="260" empty-text="没有在办的买卖">
|
||||||
<el-table-column label="状态" width="130"><template #default="s">{{ tx('insStatus', s.row.status) }}</template></el-table-column>
|
<el-table-column label="股票" min-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="90"><template #default="s"><el-button size="small" @click="cancelIns(s.row.instruction_id)">撤单</el-button></template></el-table-column>
|
<el-table-column label="动作" width="150"><template #default="s">{{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}</template></el-table-column>
|
||||||
</el-table>
|
<el-table-column label="数量 / 已成" width="120" align="right"><template #default="s"><span class="mono">{{ s.row.qty }} / {{ s.row.exec_qty||0 }}</span></template></el-table-column>
|
||||||
|
<el-table-column label="限价" width="82" align="right"><template #default="s"><span class="mono">{{ s.row.limit_price||'—' }}</span></template></el-table-column>
|
||||||
|
<el-table-column label="状态" width="118"><template #default="s"><span class="chip idle"><span class="dot"></span>{{ tx('insStatus', s.row.status) }}</span></template></el-table-column>
|
||||||
|
<el-table-column label="操作" width="76"><template #default="s"><button class="tbtn sm" @click="cancelIns(s.row.instruction_id)">撤单</button></template></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="done">
|
||||||
|
<template #label>今日成交 <span class="tabn">{{ insDone.length }}</span></template>
|
||||||
|
<el-table :data="insDone" size="small" max-height="260" empty-text="今天还没有成交">
|
||||||
|
<el-table-column label="股票" min-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="150"><template #default="s">{{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}</template></el-table-column>
|
||||||
|
<el-table-column label="数量 / 已成" width="120" align="right"><template #default="s"><span class="mono">{{ s.row.qty }} / {{ s.row.exec_qty||0 }}</span></template></el-table-column>
|
||||||
|
<el-table-column label="状态" width="120"><template #default="s"><span class="chip ok"><span class="dot"></span>{{ tx('insStatus', s.row.status) }}</span></template></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="end">
|
||||||
|
<template #label>已了结 <span class="tabn">{{ insEnd.length }}</span></template>
|
||||||
|
<el-table :data="insEnd" size="small" max-height="260" empty-text="今天没有了结的单">
|
||||||
|
<el-table-column label="股票" min-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="150"><template #default="s">{{ tx('action', s.row.action) }} · {{ tx('side', s.row.side) }}</template></el-table-column>
|
||||||
|
<el-table-column label="结束方式" min-width="150"><template #default="s"><span class="chip warn"><span class="dot"></span>{{ tx('insStatus', s.row.status) }}</span></template></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
<h3 style="margin-top:14px;cursor:pointer" @click="showLedger=!showLedger">今天发生了什么 · {{ ledger.length }} 条 <span class="muted" style="font-size:12px;font-weight:normal">{{ showLedger?'▲ 收起':'▼ 展开' }}</span></h3>
|
<h3 style="margin-top:14px;cursor:pointer" @click="showLedger=!showLedger">今天发生了什么 · {{ ledger.length }} 条 <span class="muted" style="font-size:12px;font-weight:normal">{{ showLedger?'▲ 收起':'▼ 展开' }}</span></h3>
|
||||||
<template v-if="showLedger">
|
<template v-if="showLedger">
|
||||||
<div class="muted" v-if="!ledger.length">今天还没有记录。</div>
|
<div class="muted" v-if="!ledger.length">今天还没有记录。</div>
|
||||||
<div v-for="(l,i) in ledger" :key="i" style="padding:3px 0;border-bottom:1px solid #262626">
|
<div v-for="(l,i) in ledger" :key="i" class="feed-row">
|
||||||
<span class="muted">{{ (l.decided_at||'').slice(11,16) }}</span>
|
<span class="muted mono">{{ (l.decided_at||'').slice(11,16) }}</span>
|
||||||
<b> {{ nm(l.ts_code) }}</b>:{{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }}<span v-if="l.reason" class="muted"> —— {{ l.reason }}</span>
|
<b> {{ nm(l.ts_code) }}</b>:{{ tx('arbiter', l.arbiter) }}{{ tx('verdict', l.verdict) }} {{ tx('action', l.action) }}<span v-if="l.reason" class="muted"> —— {{ l.reason }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -237,7 +319,7 @@
|
||||||
<!-- 4.5) 我的策略 + 操作日志 -->
|
<!-- 4.5) 我的策略 + 操作日志 -->
|
||||||
<div class="panel tblk">
|
<div class="panel tblk">
|
||||||
<h3>我的策略 · {{ strategies.length }} 个
|
<h3>我的策略 · {{ strategies.length }} 个
|
||||||
<el-tag size="small" :type="stratEnabled?'success':'info'" effect="dark" style="margin-left:8px">
|
<el-tag size="small" :type="stratEnabled?'primary':'info'" effect="dark" style="margin-left:8px">
|
||||||
{{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }}</el-tag>
|
{{ stratEnabled ? '策略层已启用' : '策略层总开关未开(PMS_STRATEGY_ENABLED)' }}</el-tag>
|
||||||
</h3>
|
</h3>
|
||||||
<el-alert v-if="!stratEnabled" type="info" effect="dark" :closable="false" show-icon style="margin-bottom:8px"
|
<el-alert v-if="!stratEnabled" type="info" effect="dark" :closable="false" show-icon style="margin-bottom:8px"
|
||||||
|
|
@ -248,10 +330,10 @@
|
||||||
<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"><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="自主档" 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-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="danger" effect="dark" style="margin-left:6px">买入已暂停</el-tag>
|
<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:#f56c6c;font-size:11px">决策系统风控:{{ s.row.buy_paused.reason || '资金异动' }}(卖出/平回不受影响;确认无碍点右侧「恢复买入」)</div>
|
<div v-if="s.row.buy_paused" style="color:#9a6a00;font-size:11px">决策系统风控:{{ s.row.buy_paused.reason || '资金异动' }}(卖出/平回不受影响;确认无碍点右侧「恢复买入」)</div>
|
||||||
</template></el-table-column>
|
</template></el-table-column>
|
||||||
<el-table-column label="状态" width="84"><template #default="s"><el-tag size="small" :type="s.row.status==='ACTIVE'?'success':'info'">{{ tx('stratStatus', s.row.status) }}</el-tag></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="260"><template #default="s">
|
<el-table-column label="操作" width="260"><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-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-else-if="s.row.status==='PAUSED'" size="small" type="success" @click="setStrategyStatus(s.row.strategy_id,'ACTIVE')">恢复</el-button>
|
||||||
|
|
@ -265,7 +347,7 @@
|
||||||
<div class="muted" v-if="!opLog.length">还没有操作记录。</div>
|
<div class="muted" v-if="!opLog.length">还没有操作记录。</div>
|
||||||
<div v-for="(o,i) in opLog" :key="i" style="padding:3px 0;border-bottom:1px solid #262626">
|
<div v-for="(o,i) in opLog" :key="i" style="padding:3px 0;border-bottom:1px solid #262626">
|
||||||
<span class="muted">{{ (o.at||'').slice(11,16) }}</span>
|
<span class="muted">{{ (o.at||'').slice(11,16) }}</span>
|
||||||
<el-tag size="small" effect="dark" :type="o.result==='OK'?'success':(o.result==='BLOCKED'?'danger':'warning')" style="margin:0 6px">{{ o.result }}</el-tag>
|
<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>
|
<b>{{ o.op }}</b><span v-if="o.ts_code" class="muted"> · {{ nm(o.ts_code) }}</span>
|
||||||
<span v-if="o.reason" style="color:#f56c6c"> — {{ o.reason }}</span>
|
<span v-if="o.reason" style="color:#f56c6c"> — {{ o.reason }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -441,16 +523,20 @@
|
||||||
|
|
||||||
<!-- 6) 系统在盯的候选 -->
|
<!-- 6) 系统在盯的候选 -->
|
||||||
<div class="panel tblk">
|
<div class="panel tblk">
|
||||||
<h3>系统在盯的候选(今日选股计划)<span class="muted" style="font-weight:400"> · 计划日 {{ planStatus.date || '—' }}</span></h3>
|
<h3>系统在盯的候选 <span class="muted" style="font-weight:400">· 今日选股计划 · 计划日 {{ planStatus.date || '—' }}</span></h3>
|
||||||
|
<div class="sub2">决策系统盯着、可能冒出建仓提议的票。<b style="color:var(--ink-2)">每只都标了今天为什么下单、或为什么没下单。</b></div>
|
||||||
|
<div class="pool-note" v-if="(openScan.notes||[]).length"><span v-for="(n,i) in openScan.notes" :key="i">{{ n }}<span v-if="i < openScan.notes.length-1">;</span></span></div>
|
||||||
<div class="muted" v-if="planStatus.ok===false">上游计划暂不可用。</div>
|
<div class="muted" v-if="planStatus.ok===false">上游计划暂不可用。</div>
|
||||||
<el-table v-else :data="planRows.slice(0,20)" size="small" border max-height="300" empty-text="暂无">
|
<el-table v-else :data="planRows.slice(0,20)" size="small" max-height="360" empty-text="暂无">
|
||||||
<el-table-column prop="rank" label="名次" width="60"></el-table-column>
|
<el-table-column label="#" width="52" align="right"><template #default="s"><span class="mono muted">{{ s.row.rank }}</span></template></el-table-column>
|
||||||
<el-table-column label="股票" width="160"><template #default="s"><b>{{ s.row.name || nm(s.row.ts_code) }}</b> <span class="muted mono">{{ s.row.ts_code }}</span></template></el-table-column>
|
<el-table-column label="股票" min-width="150"><template #default="s"><b>{{ s.row.name || nm(s.row.ts_code) }}</b> <span class="muted mono">{{ s.row.ts_code }}</span></template></el-table-column>
|
||||||
<el-table-column prop="theme" label="主题" width="130"></el-table-column>
|
<el-table-column label="主题" width="130"><template #default="s"><span class="tag" v-if="s.row.theme">{{ s.row.theme }}</span><span v-else class="muted">—</span></template></el-table-column>
|
||||||
<el-table-column prop="tier" label="传导档" width="90"></el-table-column>
|
<el-table-column label="传导档" width="88"><template #default="s"><span class="muted">{{ s.row.tier || '—' }}</span></template></el-table-column>
|
||||||
<el-table-column label="预期空间" width="100"><template #default="s">{{ s.row.upside==null ? '—' : ((s.row.upside>0?'+':'')+(s.row.upside*100).toFixed(0)+'%') }}</template></el-table-column>
|
<el-table-column label="处置 · 为什么" min-width="300"><template #default="s">
|
||||||
|
<span class="disp" :class="dispOf(s.row.ts_code).cls">● {{ dispOf(s.row.ts_code).label }}</span>
|
||||||
|
<div class="why" v-if="dispOf(s.row.ts_code).why">{{ dispOf(s.row.ts_code).why }}</div>
|
||||||
|
</template></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="muted" style="margin-top:6px">这是系统当前在盯、可能冒出提议的池子;仅供参考,不自动下单。</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1144,6 +1230,8 @@ createApp({
|
||||||
const instructions = ref([]), ledger = ref([]), proposals = ref([]);
|
const instructions = ref([]), ledger = ref([]), proposals = ref([]);
|
||||||
const strategies = ref([]), stratEnabled = ref(false), opLog = ref([]);
|
const strategies = ref([]), stratEnabled = ref(false), opLog = ref([]);
|
||||||
const showLedger = ref(false); // 「今天发生了什么」默认折叠
|
const showLedger = ref(false); // 「今天发生了什么」默认折叠
|
||||||
|
const openScan = ref({ by_code: {}, notes: [] });
|
||||||
|
const insTab = ref('live');
|
||||||
const stratDlg = reactive({ visible:false, busy:false, reasons:[], ts_code:'', price:0,
|
const stratDlg = reactive({ visible:false, busy:false, reasons:[], ts_code:'', price:0,
|
||||||
total_qty:0, avail_qty:0, cushion_pct:null, type:'T0', autonomy:'auto',
|
total_qty:0, avail_qty:0, cushion_pct:null, type:'T0', autonomy:'auto',
|
||||||
p:{ t_ratio:0.2, lower:0, upper:0, center:0, step_pct:0.02, per_lot:100, max_capital:0,
|
p:{ t_ratio:0.2, lower:0, upper:0, center:0, step_pct:0.02, per_lot:100, max_capital:0,
|
||||||
|
|
@ -1244,7 +1332,7 @@ createApp({
|
||||||
}[n] || n);
|
}[n] || n);
|
||||||
const stTag = s => ({ EXECUTING: 'primary', DONE: 'success', PARTIAL: 'warning',
|
const stTag = s => ({ EXECUTING: 'primary', DONE: 'success', PARTIAL: 'warning',
|
||||||
CANCELLED: 'info', EFFECTIVE: 'success', SUPERSEDED: 'info' }[s] || 'warning');
|
CANCELLED: 'info', EFFECTIVE: 'success', SUPERSEDED: 'info' }[s] || 'warning');
|
||||||
const cuTag = s => ({ SOLID: 'success', THIN: 'warning', NONE: 'danger' }[s] || 'info');
|
const cuTag = s => ({ SOLID: 'info', THIN: 'warning', NONE: 'warning' }[s] || 'info');
|
||||||
const canCancel = r => r.cmd_class === 'task' &&
|
const canCancel = r => r.cmd_class === 'task' &&
|
||||||
['PENDING', 'PLANNING', 'EXECUTING', 'PARTIAL'].includes(r.status);
|
['PENDING', 'PLANNING', 'EXECUTING', 'PARTIAL'].includes(r.status);
|
||||||
const progPct = p => {
|
const progPct = p => {
|
||||||
|
|
@ -1296,6 +1384,28 @@ createApp({
|
||||||
}
|
}
|
||||||
|
|
||||||
const heldPositions = computed(() => (positions.value || []).filter(p => (p.total_qty || 0) > 0));
|
const heldPositions = computed(() => (positions.value || []).filter(p => (p.total_qty || 0) > 0));
|
||||||
|
// ---- 今日在办分档 + 候选处置 (2026-08-12 重构新增) ----
|
||||||
|
const todayYmd = computed(() => (String(health.value.now || '').slice(0, 10).replace(/-/g, '')) || '');
|
||||||
|
const _LIVE_INS = ['PROPOSED', 'RULE_PASSED', 'JUDGE_PASSED', 'DISPATCHED'];
|
||||||
|
const _sameDayIns = r => { const y = todayYmd.value;
|
||||||
|
return !y || String(r.instruction_id || '').indexOf('INS_' + y + '_') === 0; };
|
||||||
|
const insLive = computed(() => (instructions.value || []).filter(r => _LIVE_INS.includes(r.status)));
|
||||||
|
const insDone = computed(() => (instructions.value || []).filter(r => r.status === 'CONFIRMED' && _sameDayIns(r)));
|
||||||
|
const insEnd = computed(() => (instructions.value || []).filter(r => ['EXPIRED', 'CANCELLED', 'REJECTED'].includes(r.status) && _sameDayIns(r)));
|
||||||
|
// 每只候选今天为什么下单/没下单: 已落地的事实(指令/提议)优先, 其余看 /api/open-scan 的只读处置。
|
||||||
|
function dispOf(code) {
|
||||||
|
const inst = (instructions.value || []).find(i => i.ts_code === code && i.action === 'OPEN');
|
||||||
|
if (inst) return { cls: 'done', label: '已下单', why: '在『今日在办』(' + tx('insStatus', inst.status) + ')' };
|
||||||
|
const prop = (proposals.value || []).find(p => p.ts_code === code && p.action === 'OPEN');
|
||||||
|
if (prop) return { cls: 'queue', label: '待你确认', why: '已生成提议,在『等我拍板』等你点头' };
|
||||||
|
const d = (openScan.value.by_code || {})[code];
|
||||||
|
if (d) {
|
||||||
|
if (d.disp === 'would') return { cls: 'would', label: '将建仓', why: d.why };
|
||||||
|
return { cls: 'deny', label: '被否决', why: d.why };
|
||||||
|
}
|
||||||
|
return { cls: 'wait', label: '在盯', why: '' };
|
||||||
|
}
|
||||||
|
|
||||||
const settingKeys = ['PMS_TOTAL_SCALE', 'PMS_PORTFOLIO_CAP', 'PMS_STOCK_CAP',
|
const settingKeys = ['PMS_TOTAL_SCALE', 'PMS_PORTFOLIO_CAP', 'PMS_STOCK_CAP',
|
||||||
'PMS_MAX_NAMES', 'PMS_CASH_RESERVE',
|
'PMS_MAX_NAMES', 'PMS_CASH_RESERVE',
|
||||||
'PMS_DCA_MAX_RATIO', 'PMS_DCA_TRIGGERS', 'PMS_DCA_DEEP_CONFIRM',
|
'PMS_DCA_MAX_RATIO', 'PMS_DCA_TRIGGERS', 'PMS_DCA_DEEP_CONFIRM',
|
||||||
|
|
@ -1516,7 +1626,7 @@ createApp({
|
||||||
}
|
}
|
||||||
async function loadInstructions() {
|
async function loadInstructions() {
|
||||||
const d = await call('get',
|
const d = await call('get',
|
||||||
'/api/instructions?status=PROPOSED,RULE_PASSED,JUDGE_PASSED,DISPATCHED&limit=100');
|
'/api/instructions?status=PROPOSED,RULE_PASSED,JUDGE_PASSED,DISPATCHED,CONFIRMED,EXPIRED,CANCELLED,REJECTED&limit=200');
|
||||||
instructions.value = d.data || [];
|
instructions.value = d.data || [];
|
||||||
}
|
}
|
||||||
async function loadLedger() {
|
async function loadLedger() {
|
||||||
|
|
@ -1525,6 +1635,10 @@ createApp({
|
||||||
async function loadProposals() {
|
async function loadProposals() {
|
||||||
const d = await call('get', '/api/proposals'); proposals.value = d.data || [];
|
const d = await call('get', '/api/proposals'); proposals.value = d.data || [];
|
||||||
}
|
}
|
||||||
|
async function loadOpenScan() {
|
||||||
|
const d = await call('get', '/api/open-scan');
|
||||||
|
openScan.value = (d && d.by_code) ? d : { by_code: {}, notes: [] };
|
||||||
|
}
|
||||||
async function loadPlans(cid) {
|
async function loadPlans(cid) {
|
||||||
plansOf.value = cid;
|
plansOf.value = cid;
|
||||||
const d = await call('get', '/api/plans?command_id=' + cid); plans.value = d.data || [];
|
const d = await call('get', '/api/plans?command_id=' + cid); plans.value = d.data || [];
|
||||||
|
|
@ -1559,7 +1673,7 @@ createApp({
|
||||||
loading.value = true; err.value = '';
|
loading.value = true; err.value = '';
|
||||||
await Promise.all([loadOverview(), loadParams(), loadCatalog(), loadCommands(),
|
await Promise.all([loadOverview(), loadParams(), loadCatalog(), loadCommands(),
|
||||||
loadPositions(), loadInstructions(), loadLedger(), loadProposals(),
|
loadPositions(), loadInstructions(), loadLedger(), loadProposals(),
|
||||||
loadDispatchMode(), loadWs(), loadStrategies(), loadOpLog()]);
|
loadDispatchMode(), loadWs(), loadStrategies(), loadOpLog(), loadOpenScan()]);
|
||||||
await loadNames();
|
await loadNames();
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
wsPollSync();
|
wsPollSync();
|
||||||
|
|
@ -1774,7 +1888,8 @@ createApp({
|
||||||
pmap, pval, dcaOn, sumPosition, sumDca, sumAutonomy,
|
pmap, pval, dcaOn, sumPosition, sumDca, sumAutonomy,
|
||||||
strategies, stratEnabled, opLog, stratDlg, stratQty, loadStrategies, loadOpLog,
|
strategies, stratEnabled, opLog, stratDlg, stratQty, loadStrategies, loadOpLog,
|
||||||
openStrategy, validateStrategy, attachStrategy, setStrategyStatus, stratStateText, resumeBuy,
|
openStrategy, validateStrategy, attachStrategy, setStrategyStatus, stratStateText, resumeBuy,
|
||||||
showLedger, onPosExpand };
|
showLedger, onPosExpand,
|
||||||
|
openScan, insTab, todayYmd, insLive, insDone, insEnd, dispOf, loadOpenScan };
|
||||||
}
|
}
|
||||||
}).use(ElementPlus).mount('#app');
|
}).use(ElementPlus).mount('#app');
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue