Add responsive mobile layout, records cards, and tablet settings fold fix.
Mobile gets compact trade/records UI with detail modals; static assets are cache-busted and settings cards fold correctly on tablet grid layout. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+39
-8
@@ -24,11 +24,32 @@
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/tech.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}">
|
||||
<script>
|
||||
(function () {
|
||||
var ua = navigator.userAgent || '';
|
||||
var isIpad = /iPad/i.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||
var isTabletUa = isIpad || (/Android/i.test(ua) && !/Mobile/i.test(ua));
|
||||
var isPhoneUa = !isTabletUa && (/iPhone|iPod|Android.*Mobile|HarmonyOS|OpenHarmony|Mobile/i.test(ua));
|
||||
var s = Math.min(window.screen.width || 0, window.screen.height || 0);
|
||||
var coarse = window.matchMedia('(hover: none) and (pointer: coarse)').matches;
|
||||
var layout = 'desktop';
|
||||
if (isPhoneUa || (s > 0 && s < 600)) layout = 'phone';
|
||||
else if (isTabletUa || (s >= 600 && s <= 1100 && coarse)) layout = 'tablet';
|
||||
else if (window.innerWidth <= 767) layout = 'phone';
|
||||
var root = document.documentElement;
|
||||
root.dataset.layout = layout;
|
||||
root.dataset.mobile = layout === 'phone' ? '1' : '0';
|
||||
root.dataset.orientation = layout === 'phone' ? 'portrait' : (window.innerWidth >= window.innerHeight ? 'landscape' : 'portrait');
|
||||
if (layout === 'phone') root.classList.add('layout-phone');
|
||||
else if (layout === 'tablet') root.classList.add('layout-tablet');
|
||||
})();
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/theme.js') }}?v={{ asset_v }}"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}?v={{ asset_v }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/tech.css') }}?v={{ asset_v }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/responsive.css') }}?v={{ asset_v }}">
|
||||
{% block extra_css %}{% endblock %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/mobile.css') }}?v={{ asset_v }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="tech-bg" aria-hidden="true">
|
||||
@@ -43,6 +64,10 @@
|
||||
<button type="button" class="nav-toggle" id="nav-toggle" aria-label="打开菜单" aria-expanded="false" aria-controls="site-nav">
|
||||
<span></span><span></span><span></span>
|
||||
</button>
|
||||
<h1 class="site-title">
|
||||
<span class="site-title-mobile">期货监控</span>
|
||||
<span class="site-title-desktop">国内期货 · 交易复盘系统<span class="site-title-sub">Position Management · Disciplined Execution</span></span>
|
||||
</h1>
|
||||
<div class="header-tools">
|
||||
<div class="theme-switch" role="group" aria-label="主题模式">
|
||||
<button type="button" class="theme-switch-btn" data-theme-pick="dark">深色</button>
|
||||
@@ -53,7 +78,6 @@
|
||||
<div class="user-bar">{{ session.username or '用户' }}<a href="{{ url_for('logout') }}">退出</a></div>
|
||||
</div>
|
||||
<p class="pwa-ios-hint" id="pwa-ios-hint">iOS 安装:Safari 浏览器点击底部分享按钮,选择「添加到主屏幕」。</p>
|
||||
<h1 class="site-title">国内期货 · 交易复盘系统<span class="site-title-sub">Position Management · Disciplined Execution</span></h1>
|
||||
<button type="button" class="nav-backdrop" id="nav-backdrop" aria-label="关闭菜单" hidden></button>
|
||||
<nav class="site-nav" id="site-nav">
|
||||
<a href="{{ url_for('positions') }}" class="{% if request.endpoint in ('positions', 'trade_page', 'recommend_page') %}active{% endif %}">下单监控</a>
|
||||
@@ -73,9 +97,16 @@
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/symbol.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nav.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/pwa.js') }}"></script>
|
||||
<div id="orientation-lock" class="orientation-lock" hidden>
|
||||
<div class="orientation-lock-box">
|
||||
<div class="orientation-lock-icon" aria-hidden="true">↻</div>
|
||||
<p id="orientation-lock-msg">请旋转设备</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ url_for('static', filename='js/orientation.js') }}?v={{ asset_v }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/symbol.js') }}?v={{ asset_v }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nav.js') }}?v={{ asset_v }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/pwa.js') }}?v={{ asset_v }}"></script>
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+107
-5
@@ -1,7 +1,11 @@
|
||||
{# Copyright (c) 2025-2026 马建军. All rights reserved. 专有软件,详见 LICENSE.zh-CN.txt #}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}交易记录与复盘 - 国内期货 · 交易复盘系统{% endblock %}
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/records.css') }}?v={{ asset_v }}">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="records-page">
|
||||
<div class="card records-equity-card" style="margin-bottom:1.25rem">
|
||||
<h2>资金曲线</h2>
|
||||
<div class="card-body">
|
||||
@@ -20,11 +24,61 @@
|
||||
{% else %}
|
||||
<p class="hint" style="margin-top:0">CTP 未连接时仅显示本地数据库记录;连接后打开本页会自动同步柜台成交。</p>
|
||||
{% endif %}
|
||||
<label class="trade-switch-label">
|
||||
<label class="trade-switch-label records-desktop-only">
|
||||
<input type="checkbox" id="trade-edit-switch">
|
||||
<span>修改/核对开关(开启后可编辑关键字段)</span>
|
||||
</label>
|
||||
<div class="trade-table-wrap">
|
||||
<div class="records-mobile-list" id="records-trade-mobile">
|
||||
{% for t in trades %}
|
||||
<button type="button" class="records-mobile-item records-trade-item" data-trade='{{ {
|
||||
"symbol": t.symbol_name or t.symbol,
|
||||
"symbol_code": t.symbol,
|
||||
"monitor_type": t.monitor_type,
|
||||
"source": "柜台" if t.source == "ctp" else "本地",
|
||||
"direction": "做多" if t.direction == "long" else "做空",
|
||||
"entry_price": t.entry_price,
|
||||
"stop_loss": t.stop_loss,
|
||||
"take_profit": t.take_profit,
|
||||
"lots": t.lots,
|
||||
"margin": t.margin,
|
||||
"margin_pct": t.margin_pct,
|
||||
"holding_minutes": t.holding_minutes or 0,
|
||||
"open_time": t.open_time,
|
||||
"close_time": t.close_time,
|
||||
"pnl": t.pnl,
|
||||
"fee": t.fee,
|
||||
"pnl_net": t.pnl_net,
|
||||
"equity_after": t.equity_after,
|
||||
"result": t.result,
|
||||
"verified": t.verified,
|
||||
"fill_review_url": url_for("fill_review_from_trade", tid=t.id),
|
||||
"del_url": url_for("del_trade", tid=t.id)
|
||||
} | tojson }}'>
|
||||
<div class="records-mobile-item-head">
|
||||
<span class="records-mobile-symbol">{{ t.symbol_name or t.symbol }}</span>
|
||||
<span class="badge dir">{{ '做多' if t.direction == 'long' else '做空' }}</span>
|
||||
</div>
|
||||
<div class="records-mobile-item-meta">
|
||||
<span>{{ (t.close_time or t.open_time or '')[:16].replace('T', ' ') }}</span>
|
||||
{% if t.result == '止盈' %}<span class="badge profit">{{ t.result }}</span>
|
||||
{% elif t.result == '止损' %}<span class="badge loss">{{ t.result }}</span>
|
||||
{% elif t.result in ('移动止盈', '保本止盈') %}<span class="badge profit">{{ t.result }}</span>
|
||||
{% elif t.result == '手动平仓' %}<span class="badge result-manual">{{ t.result }}</span>
|
||||
{% else %}<span class="badge result-external">{{ t.result }}</span>{% endif %}
|
||||
<span>{{ '柜台' if t.source == 'ctp' else '本地' }}</span>
|
||||
</div>
|
||||
<div class="records-mobile-item-foot">
|
||||
<span class="records-mobile-pnl {{ 'is-profit' if t.pnl_net and t.pnl_net > 0 else ('is-loss' if t.pnl_net and t.pnl_net < 0 else 'is-flat') }}">
|
||||
净盈亏 {{ t.pnl_net if t.pnl_net is not none else '-' }}
|
||||
</span>
|
||||
<span class="records-mobile-chevron">查看详情 ›</span>
|
||||
</div>
|
||||
</button>
|
||||
{% else %}
|
||||
<p class="records-mobile-empty">暂无交易记录</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="trade-table-wrap records-desktop-only">
|
||||
<table class="trade-table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -243,7 +297,45 @@
|
||||
<button type="submit" class="btn-primary">筛选</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<div class="card-scroll">
|
||||
<div class="records-mobile-list records-review-mobile">
|
||||
{% for r in reviews %}
|
||||
<button type="button" class="records-mobile-item review-view-btn{% if r.is_emotion %} is-emotion{% endif %}" data-review='{{ {
|
||||
"symbol": r.symbol_name or r.symbol, "symbol_code": r.symbol,
|
||||
"direction": "做多" if r.direction=="long" else "做空",
|
||||
"lots": r.lots, "timeframe": r.timeframe,
|
||||
"entry_price": r.entry_price, "stop_loss": r.stop_loss, "take_profit": r.take_profit,
|
||||
"close_price": r.close_price,
|
||||
"open_time": r.open_time, "close_time": r.close_time,
|
||||
"holding_duration": r.holding_duration,
|
||||
"initial_pnl": r.initial_pnl, "actual_pnl": r.actual_pnl, "pnl": r.pnl,
|
||||
"fee": r.fee, "pnl_net": r.pnl_net,
|
||||
"open_type": r.open_type,
|
||||
"exit_trigger": r.exit_trigger, "exit_supplement": r.exit_supplement,
|
||||
"watch_after_breakeven": r.watch_after_breakeven,
|
||||
"new_position_while_occupied": r.new_position_while_occupied,
|
||||
"is_emotion": r.is_emotion, "behavior_tags": r.behavior_tags,
|
||||
"notes": r.notes, "screenshot": r.screenshot
|
||||
} | tojson }}'>
|
||||
<div class="records-mobile-item-head">
|
||||
<span class="records-mobile-symbol">{{ r.symbol_name or r.symbol }}</span>
|
||||
<span class="badge dir">{{ '多' if r.direction == 'long' else '空' }}</span>
|
||||
</div>
|
||||
<div class="records-mobile-item-meta">
|
||||
<span>{{ r.close_time[:16].replace('T', ' ') if r.close_time else '' }}</span>
|
||||
{% if r.is_emotion %}<span class="badge emotion">情绪单</span>{% endif %}
|
||||
</div>
|
||||
<div class="records-mobile-item-foot">
|
||||
<span class="records-mobile-pnl {{ 'is-profit' if r.pnl_net and r.pnl_net > 0 else ('is-loss' if r.pnl_net and r.pnl_net < 0 else 'is-flat') }}">
|
||||
净盈亏 {{ r.pnl_net if r.pnl_net is not none else '-' }}
|
||||
</span>
|
||||
<span class="records-mobile-chevron">查看详情 ›</span>
|
||||
</div>
|
||||
</button>
|
||||
{% else %}
|
||||
<p class="records-mobile-empty">暂无复盘记录</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="card-scroll records-desktop-only">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -307,6 +399,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="trade-detail-modal" class="modal-mask">
|
||||
<div class="modal-box review-modal-fullscreen">
|
||||
<span class="modal-close">✕</span>
|
||||
<h3>交易详情</h3>
|
||||
<div id="trade-detail-modal-body" class="review-modal-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if auto_records %}
|
||||
<div class="card" style="margin-top:1rem">
|
||||
<h2>系统自动记录(止盈/止损)</h2>
|
||||
@@ -327,13 +427,15 @@
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script src="https://unpkg.com/lightweight-charts@4.2.0/dist/lightweight-charts.standalone.production.js"></script>
|
||||
<script>window.__EQUITY_CURVE__ = {{ equity_curve | default([]) | tojson }};</script>
|
||||
<script src="{{ url_for('static', filename='js/equity_curve.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/review.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/trades.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/review.js') }}?v={{ asset_v }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/records.js') }}?v={{ asset_v }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/trades.js') }}?v={{ asset_v }}"></script>
|
||||
{% if prefill %}
|
||||
<script>
|
||||
function bootReviewPrefill() {
|
||||
|
||||
+10
-5
@@ -4,8 +4,13 @@
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.settings-page{display:flex;flex-direction:column;gap:1.25rem}
|
||||
.settings-page .split-grid{margin-bottom:0}
|
||||
.settings-page .split-grid .card{margin-bottom:0;min-height:100%;height:100%;display:flex;flex-direction:column}
|
||||
.settings-page .split-grid{margin-bottom:0;align-items:start}
|
||||
.settings-page .split-grid .card:not(.settings-fold){margin-bottom:0;min-height:100%;height:100%;display:flex;flex-direction:column}
|
||||
.settings-page .split-grid .settings-fold.card,
|
||||
.settings-page .split-grid .settings-ctp-fold.card{
|
||||
margin-bottom:0;min-height:auto !important;height:auto !important;align-self:start;
|
||||
display:flex;flex-direction:column;
|
||||
}
|
||||
.settings-page .split-grid .card > form,
|
||||
.settings-page .split-grid .card > .card-inner,
|
||||
.settings-page .split-grid .settings-fold-body > form,
|
||||
@@ -122,7 +127,7 @@
|
||||
.settings-ai-daily-grid{grid-template-columns:1fr}
|
||||
}
|
||||
.settings-page .settings-fold.card{padding:0;overflow:hidden}
|
||||
.settings-page .split-grid .settings-fold.card{min-height:auto;height:auto}
|
||||
.settings-page .split-grid .settings-fold.card{min-height:auto;height:auto;align-self:start}
|
||||
.settings-fold-head{
|
||||
width:100%;display:flex;align-items:center;justify-content:space-between;gap:.75rem;
|
||||
padding:1rem 1rem .85rem;margin:0;border:none;background:transparent;cursor:pointer;
|
||||
@@ -140,7 +145,7 @@
|
||||
}
|
||||
.settings-fold-chevron{flex-shrink:0;font-size:.72rem;color:var(--text-muted);transition:transform .2s ease}
|
||||
.settings-fold.is-collapsed .settings-fold-chevron{transform:rotate(-90deg)}
|
||||
.settings-fold-body{padding:0 1rem 1rem;flex:1;display:flex;flex-direction:column}
|
||||
.settings-fold-body{padding:0 1rem 1rem;display:flex;flex-direction:column}
|
||||
.settings-fold.is-collapsed .settings-fold-body{display:none}
|
||||
.settings-admin-row .settings-fold-head{padding:.75rem .85rem .6rem}
|
||||
.settings-admin-row .settings-fold-title{font-size:.95rem}
|
||||
@@ -607,5 +612,5 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/settings.js') }}?v={{ asset_v }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
.strategy-preview{background:var(--card-inner);border:1px solid var(--card-border);border-radius:8px;padding:.65rem .85rem;font-size:.78rem;line-height:1.5;margin-top:.75rem;max-height:360px;overflow:auto}
|
||||
.strategy-preview .trend-summary{margin-bottom:.45rem;color:var(--text-title);font-size:.8rem;line-height:1.55}
|
||||
.strategy-preview .trend-detail{margin-bottom:.55rem;color:var(--text-muted);font-size:.75rem;line-height:1.5}
|
||||
.strategy-preview-table{width:100%;border-collapse:collapse;font-size:.72rem}
|
||||
.strategy-preview-table{width:100%;border-collapse:collapse;font-size:.72rem;min-width:520px}
|
||||
.strategy-preview-table th,.strategy-preview-table td{padding:.35rem .4rem;border-bottom:1px solid var(--table-border);text-align:right;white-space:nowrap}
|
||||
.strategy-preview-table th:first-child,.strategy-preview-table td:first-child{text-align:left}
|
||||
.strategy-preview-table thead th{color:var(--text-muted);font-weight:600;background:var(--list-item-bg)}
|
||||
@@ -148,6 +148,7 @@
|
||||
{% endif %}
|
||||
<h3 style="font-size:.85rem;margin:1rem 0 .45rem">活跃滚仓组</h3>
|
||||
{% if roll_groups %}
|
||||
<div class="table-responsive">
|
||||
<table class="strategy-preview-table">
|
||||
<thead><tr>
|
||||
<th>ID</th><th>品种</th><th>方向</th><th>腿数</th><th>首仓TP</th><th>当前SL</th><th>当前均价</th><th>止盈盈利(元)</th>
|
||||
@@ -167,11 +168,13 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint text-muted">暂无</p>
|
||||
{% endif %}
|
||||
<h3 style="font-size:.85rem;margin:1rem 0 .45rem">最近滚仓腿</h3>
|
||||
{% if roll_legs %}
|
||||
<div class="table-responsive">
|
||||
<table class="strategy-preview-table">
|
||||
<thead><tr>
|
||||
<th>#</th><th>组</th><th>方式</th><th>手数</th><th>触发/限价</th><th>新SL</th><th>状态</th><th>操作</th>
|
||||
@@ -191,6 +194,7 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="hint text-muted">暂无</p>
|
||||
{% endif %}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}下单监控 - 国内期货 · 交易复盘系统{% endblock %}
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/trade.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/trade.css') }}?v={{ asset_v }}">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="trade-page">
|
||||
|
||||
Reference in New Issue
Block a user