修改页面布局样式

This commit is contained in:
zlt 2026-08-13 10:00:46 +08:00
parent 7b7eef674d
commit abfeff22cb
1 changed files with 43 additions and 8 deletions

View File

@ -113,7 +113,7 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
<div class="hd">
<h1>PMS 持仓管理<span class="ver">v{{ health.version || '-' }} · {{ health.now || '' }}</span></h1>
<span class="chip" :class="health.trade_day?'ok':'idle'"><span class="dot"></span>{{ health.trade_day ? '交易日':'非交易日' }}</span>
<span class="chip" :class="marketOpen?'ok':'idle'"><span class="dot"></span>{{ marketState }}</span>
<span class="chip" :class="ov.buy_halt?'warn':'ok'"><span class="dot"></span>买入 {{ ov.buy_halt ? '已暂停':'正常' }}</span>
<span class="chip" :class="ov.exec_halt?'warn':'ok'"><span class="dot"></span>执行 {{ ov.exec_halt ? '已暂停':'正常' }}</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>
@ -127,6 +127,8 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
<button class="tbtn" @click="openPlan">上游计划</button>
<button class="tbtn" @click="openReport">日报</button>
<button class="tbtn" v-show="mode==='ops'" @click="opsDrawer=true">运维</button>
<span class="muted" style="font-size:11.5px;cursor:pointer" @click="autoRefresh=!autoRefresh"
:title="autoRefresh?'自动刷新开,点此关闭':'自动刷新关,点此开启'">{{ autoRefresh ? '自动' : '手动' }}<span v-if="lastRefresh"> · {{ lastRefresh }}</span></span>
<button class="tbtn pri" :disabled="loading" @click="loadAll">{{ loading ? '刷新中…' : '刷新' }}</button>
</div>
@ -139,9 +141,12 @@ pre.json{background:var(--surface-2);border:1px solid var(--hair);border-radius:
<el-alert v-if="ov.sector_ready===false" class="banner" type="warning" effect="dark" show-icon
:closable="false"
title="行业划分数据源未配置 —— 行业集中度硬拦截已停用, 行业类命令置灰 (设计 §5)"></el-alert>
<el-alert v-if="ov.price_missing && ov.price_missing.length" class="banner" type="warning"
effect="dark" show-icon :closable="false"
:title="'以下持仓取不到实时价, 已用摊薄成本兜底: ' + ov.price_missing.join(', ')"></el-alert>
<el-alert v-if="marketOpen && ov.price_missing && ov.price_missing.length" class="banner" type="warning"
show-icon :closable="false"
:title="'以下持仓取不到实时价(停牌或行情中断),已用摊薄成本兜底: ' + ov.price_missing.join(', ')"></el-alert>
<el-alert v-if="!marketOpen && ov.price_missing && ov.price_missing.length" class="banner" type="info"
show-icon :closable="false"
:title="'现在' + marketState + ',行情未刷新;持仓盈亏与安全垫按最近收盘价/成本估算,不是实时。'"></el-alert>
<el-alert v-if="health.calendar_degraded" class="banner" type="warning" effect="dark" show-icon
:closable="false" title="交易日历降级: 未安装 chinesecalendar, 节假日不可辨"></el-alert>
<el-alert v-if="dm.shadow" class="banner" type="info" effect="dark" show-icon :closable="false"
@ -1252,6 +1257,8 @@ createApp({
const showLedger = ref(false); // 「今天发生了什么」默认折叠
const showOpLog = ref(false); // 操作日志默认折叠
const showSettings = ref(false); // 设置默认折叠
const lastRefresh = ref('');
const autoRefresh = ref(true);
const openScan = ref({ by_code: {}, notes: [] });
const insTab = ref('live');
const stratDlg = reactive({ visible:false, busy:false, reasons:[], ts_code:'', price:0,
@ -1408,6 +1415,16 @@ createApp({
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, '')) || '');
// 是否处于连续交易时段 (09:30-11:30 / 13:00-15:00 的交易日)。缺实时价在盘中才是问题,
// 休市/非交易日本就没有实时行情, 不该报警 —— 2026-08-12 用户提。
const marketOpen = computed(() => {
if (!health.value.trade_day) return false;
const t = (health.value.now || '').slice(11, 16);
if (!t) return false;
return (t >= '09:30' && t <= '11:30') || (t >= '13:00' && t <= '15:00');
});
const marketState = computed(() =>
!health.value.trade_day ? '非交易日' : (marketOpen.value ? '盘中' : '休市'));
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; };
@ -1448,8 +1465,8 @@ createApp({
if (o.buy_halt) out.push('已暂停买入(卖出与止损不受影响)');
if (o.exec_halt) out.push('休假模式:所有自动动作暂停,仅保留对账与日报');
if (o.brake_until) out.push('组合刹车中(解除日 ' + o.brake_until + '');
if ((o.price_missing || []).length)
out.push(o.price_missing.length + ' 只取不到实时价(停牌),其盈亏与安全垫暂不可用');
if (marketOpen.value && (o.price_missing || []).length)
out.push(o.price_missing.length + ' 只取不到实时价(停牌或行情中断),其盈亏与安全垫暂不可用');
if (o.sector_ready === false) out.push('行业数据未就绪,行业类操作暂不可用');
const j = (dm.value || {}).judge;
if (j && j.available === false) out.push('决策系统暂不可用:补足/加仓/补仓一律降级为需你确认');
@ -1703,6 +1720,7 @@ createApp({
loadPositions(), loadInstructions(), loadLedger(), loadProposals(),
loadDispatchMode(), loadWs(), loadStrategies(), loadOpLog(), loadOpenScan()]);
await loadNames();
lastRefresh.value = (health.value.now || '').slice(11, 19);
loading.value = false;
wsPollSync();
}
@ -1896,7 +1914,24 @@ createApp({
reportDrawer.value = true;
}
onMounted(() => { loadAll(); loadPlan(); }); // 计划状态并行拉, 不阻塞首屏
// —— 自动刷新: 盘中 30s、休市 5min; 只拉快变数据, 不动 params(免得冲掉设置里在改的输入) ——
let refreshTimer = null, refreshTick = 0;
async function refreshLive() {
await Promise.all([loadOverview(), loadPositions(), loadInstructions(), loadLedger(),
loadProposals(), loadStrategies(), loadOpLog(), loadOpenScan()]);
await loadNames();
lastRefresh.value = (health.value.now || '').slice(11, 19);
}
function startAutoRefresh() {
if (refreshTimer) return;
refreshTimer = setInterval(() => {
if (!autoRefresh.value) return;
refreshTick++;
if (marketOpen.value || refreshTick % 10 === 0) refreshLive();
}, 30000);
}
onUnmounted(() => { if (refreshTimer) clearInterval(refreshTimer); });
onMounted(() => { loadAll(); loadPlan(); startAutoRefresh(); }); // 首屏 + 启动自动刷新
return { tab, loading, err, health, ov, params, catalog, commands, plans, plansOf,
positions, lots, lotsOf, instructions, ledger, proposals, report, reportDrawer,
opsDrawer, opsResult, opsLoading, issuing, form, curSpec, dirtyCount, dm,
@ -1918,7 +1953,7 @@ createApp({
openStrategy, validateStrategy, attachStrategy, setStrategyStatus, stratStateText, resumeBuy,
showLedger, onPosExpand,
openScan, insTab, todayYmd, insLive, insDone, insEnd, dispOf, loadOpenScan, denyToday,
showOpLog, showSettings, watchCandidates };
showOpLog, showSettings, watchCandidates, marketOpen, marketState, lastRefresh, autoRefresh };
}
}).use(ElementPlus).mount('#app');
</script>