增加手机端自适应

This commit is contained in:
dekun
2026-05-25 07:46:45 +08:00
parent 7beeb3500c
commit e89708726f
5 changed files with 367 additions and 17 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ HUB_BRIDGE_TOKEN = (os.getenv("HUB_BRIDGE_TOKEN") or os.getenv("CONTROL_TOKEN")
_trust_raw = (os.getenv("HUB_TRUST_LAN", "true") or "").strip().lower()
HUB_TRUST_LAN = _trust_raw not in ("0", "false", "no", "off")
DIR = Path(__file__).resolve().parent
HUB_BUILD = "20260525-fs-pos-row"
HUB_BUILD = "20260525-mobile"
def _is_local(host: str | None) -> bool:
+323 -8
View File
@@ -604,16 +604,73 @@ body.hub-fullscreen-open {
margin-bottom: 14px;
}
/* 全屏放大:持仓卡片横向排列 */
/* 全屏放大:持仓卡片横向排列,列数随仓位数量自适应 */
.exchange-fullscreen .hub-pos-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 14px;
align-items: start;
align-items: stretch;
width: 100%;
}
.exchange-fullscreen .hub-pos-list.count-1 {
grid-template-columns: minmax(0, 1fr);
}
.exchange-fullscreen .hub-pos-list.count-1 .hub-pos-card.pos-card {
max-width: min(960px, 100%);
margin-inline: auto;
width: 100%;
}
.exchange-fullscreen .hub-pos-list.count-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.exchange-fullscreen .hub-pos-list.count-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.exchange-fullscreen .hub-pos-list.count-4 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.exchange-fullscreen .hub-pos-list.count-5,
.exchange-fullscreen .hub-pos-list.count-6 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.exchange-fullscreen .hub-pos-list.count-many {
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.exchange-fullscreen .hub-pos-card.pos-card {
min-width: 0;
height: 100%;
}
@media (max-width: 1100px) {
.exchange-fullscreen .hub-pos-list.count-3,
.exchange-fullscreen .hub-pos-list.count-5,
.exchange-fullscreen .hub-pos-list.count-6 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.exchange-fullscreen .hub-pos-list.count-many {
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
}
@media (max-width: 640px) {
.exchange-fullscreen .hub-pos-list.count-2,
.exchange-fullscreen .hub-pos-list.count-3,
.exchange-fullscreen .hub-pos-list.count-4,
.exchange-fullscreen .hub-pos-list.count-5,
.exchange-fullscreen .hub-pos-list.count-6,
.exchange-fullscreen .hub-pos-list.count-many {
grid-template-columns: minmax(0, 1fr);
}
.exchange-fullscreen .hub-pos-list.count-1 .hub-pos-card.pos-card {
max-width: 100%;
}
}
/* 对齐实盘「实时持仓」pos-card */
@@ -1132,8 +1189,15 @@ button.btn-sm {
gap: 8px;
}
.table-scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
max-width: 100%;
}
.data-table {
width: 100%;
min-width: 300px;
border-collapse: collapse;
font-size: 11px;
}
@@ -1436,16 +1500,267 @@ body.login-page {
font-size: 10px;
}
/* —— 手机 / 窄屏自适应 —— */
@media (max-width: 720px) {
.app-shell {
padding: 0 12px 32px;
padding: 0 max(12px, env(safe-area-inset-right)) max(28px, env(safe-area-inset-bottom))
max(12px, env(safe-area-inset-left));
}
.grid-monitor,
.settings-grid-wrap {
grid-template-columns: 1fr;
.app-header {
flex-direction: column;
align-items: stretch;
gap: 12px;
padding: 14px 0;
}
.header-right {
width: 100%;
justify-content: space-between;
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.sys-pill {
align-self: flex-start;
}
.top-nav {
width: 100%;
justify-content: stretch;
}
.top-nav a {
flex: 1;
text-align: center;
padding: 10px 12px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
}
button.ghost#btn-logout {
width: 100%;
min-height: 44px;
}
.page-head {
margin: 16px 0 12px;
}
.page-head h1 {
font-size: 17px;
flex-wrap: wrap;
}
.toolbar {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.toolbar-spacer {
display: none;
}
.toolbar-meta {
text-align: center;
order: 10;
}
.toolbar button,
.toolbar .chk-label {
width: 100%;
justify-content: center;
min-height: 44px;
}
.grid-monitor,
.settings-grid-wrap {
grid-template-columns: minmax(0, 1fr) !important;
gap: 12px;
}
.card-head {
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.card-actions {
flex-wrap: wrap;
width: 100%;
gap: 8px;
}
.card-actions .btn-link,
.card-actions button {
flex: 1 1 calc(50% - 4px);
min-height: 40px;
text-align: center;
justify-content: center;
}
.card-body {
padding: 12px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.stat-row {
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.stat-value {
font-size: 15px;
}
.exchange-fullscreen {
padding: max(10px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right))
max(16px, env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left));
}
.exchange-fullscreen-panel {
max-width: 100%;
}
.fs-head {
flex-direction: column;
align-items: stretch;
gap: 12px;
}
.fs-head-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
width: 100%;
}
.fs-head-actions .btn-expand-back {
grid-column: 1 / -1;
}
.fs-head-actions .btn-link,
.fs-head-actions button {
min-height: 44px;
text-align: center;
justify-content: center;
}
.hub-pos-card .pos-card-head {
flex-direction: column;
align-items: stretch;
}
.hub-pos-card .pos-head-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
width: 100%;
}
.hub-pos-card .pos-entrust-btn,
.hub-pos-card .pos-close-btn {
width: 100%;
min-height: 44px;
text-align: center;
}
.hub-pos-card .pos-ex-order-row {
flex-direction: column;
align-items: stretch;
gap: 6px;
}
.settings-grid {
grid-template-columns: 1fr;
}
.settings-card-foot {
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.settings-card-foot .field {
max-width: none;
}
.modal {
padding: max(12px, env(safe-area-inset-top)) 12px max(12px, env(safe-area-inset-bottom));
align-items: flex-end;
}
.modal-panel {
max-width: none;
width: 100%;
border-radius: 12px 12px 0 0;
max-height: 90vh;
overflow-y: auto;
}
.modal-actions {
flex-direction: column-reverse;
}
.modal-actions button {
width: 100%;
min-height: 44px;
}
#toast {
left: 12px;
right: 12px;
bottom: max(12px, env(safe-area-inset-bottom));
max-width: none;
}
body.login-page {
padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
}
.login-panel {
padding: 22px 18px;
}
}
@media (max-width: 480px) {
body {
font-size: 12px;
}
.brand-title {
font-size: 13px;
}
.stat-row {
grid-template-columns: 1fr;
}
.card-actions .btn-link,
.card-actions button {
flex: 1 1 100%;
}
.fs-head-actions {
grid-template-columns: 1fr;
}
.pos-action-group {
flex-direction: column;
align-items: stretch;
width: 100%;
}
.pos-action-group .btn-sm {
width: 100%;
min-height: 44px;
}
.data-table .td-actions {
white-space: normal;
}
}
+38 -3
View File
@@ -61,6 +61,14 @@
return n > 0 ? "pnl-pos" : "pnl-neg";
}
/** 全屏持仓区:按仓位数量附加布局 class(1~6 固定列数,7+ 自动填充) */
function hubPosListCountClass(n) {
const c = Math.max(0, parseInt(n, 10) || 0);
if (c <= 0) return "count-0";
if (c <= 6) return `count-${c}`;
return "count-many";
}
function currentPage() {
const p = window.location.pathname.replace(/\/$/, "") || "/monitor";
if (p.includes("settings")) return "settings";
@@ -103,9 +111,17 @@
return (settingsCache?.exchanges || []).filter((x) => x.enabled);
}
/** 监控卡片列数:3 个一行;4 个 2×2;5/6 个两行(每行最多 3) */
function isMobileLayout() {
return window.matchMedia("(max-width: 720px)").matches;
}
/** 监控卡片列数:桌面 3/2 列;手机端固定单列 */
function syncMonitorGridColumns(gridEl, count) {
if (!gridEl) return;
if (isMobileLayout()) {
gridEl.style.gridTemplateColumns = "minmax(0, 1fr)";
return;
}
let cols = 3;
if (count <= 1) cols = 1;
else if (count === 2) cols = 2;
@@ -115,6 +131,19 @@
gridEl.style.gridTemplateColumns = `repeat(${cols}, minmax(0, 1fr))`;
}
function initMobileLayout() {
let resizeTimer = null;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
const box = document.getElementById("monitor-grid");
if (box && lastMonitorRows.length) {
syncMonitorGridColumns(box, lastMonitorRows.length);
}
}, 120);
});
}
function normSym(s) {
return String(s || "")
.toUpperCase()
@@ -538,6 +567,7 @@
const slAttr = esc(String(guess.sl)).replace(/"/g, "&quot;");
const tpAttr = esc(String(guess.tp)).replace(/"/g, "&quot;");
return `<div class="pos-block">
<div class="table-scroll">
<table class="data-table"><thead><tr><th>合约</th><th></th><th></th><th></th><th></th></tr></thead><tbody>
<tr>
<td>${esc(x.symbol)}</td>
@@ -552,6 +582,7 @@
</td>
</tr>
</tbody></table>
</div>
${renderOrdersCollapse(exchangeId, x.symbol, cond, reg)}
</div>`;
}
@@ -644,8 +675,11 @@
<div class="stat-box"><div class="stat-label">余额</div><div class="stat-value">${fmt(ag.balance_usdt, 2)} U</div></div>
<div class="stat-box"><div class="stat-label">浮盈合计</div><div class="stat-value ${pnlCls(ag.total_unrealized_pnl)}">${fmt(ag.total_unrealized_pnl, 4)}</div></div>
</div>`;
html += '<div class="section-title">持仓(每币种一卡)</div><div class="hub-pos-list">';
if (pos.length) {
const posCount = pos.length;
const posListCls = hubPosListCountClass(posCount);
html += `<div class="section-title">持仓(${posCount} 仓 · 每币种一卡)</div>`;
html += `<div class="hub-pos-list ${posListCls}" data-pos-count="${posCount}">`;
if (posCount) {
pos.forEach((p) => {
html += renderLivePositionCard(row.id, p, findMonitorOrder(orders, p.symbol, p.side));
});
@@ -1087,6 +1121,7 @@
initTpslModal();
initFullscreen();
initMobileLayout();
initAuth().then((ok) => {
if (!ok) return;
+3 -3
View File
@@ -2,12 +2,12 @@
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>复盘系统中控</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/assets/app.css?v=20260525-fs-pos-row" />
<link rel="stylesheet" href="/assets/app.css?v=20260525-mobile" />
</head>
<body>
<div class="app-bg" aria-hidden="true"></div>
@@ -108,6 +108,6 @@
</div>
<div id="toast"></div>
<script src="/assets/app.js?v=20260525-fs-fix"></script>
<script src="/assets/app.js?v=20260525-mobile"></script>
</body>
</html>
+2 -2
View File
@@ -2,12 +2,12 @@
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>登录 · 复盘系统中控</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/assets/app.css" />
<link rel="stylesheet" href="/assets/app.css?v=20260525-mobile" />
</head>
<body class="login-page">
<div class="login-bg" aria-hidden="true"></div>