Align tablet trade records with close-record layout and row actions.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+108
-35
@@ -140,66 +140,139 @@
|
||||
border-color: rgba(239, 68, 68, .35);
|
||||
}
|
||||
|
||||
/* 平板横屏:每条记录单行展示,右侧保留「详情」 */
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item {
|
||||
/* 交易记录简洁行(对齐数据看板平仓记录) */
|
||||
.records-trade-row {
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 12px;
|
||||
background: var(--card-inner);
|
||||
padding: .75rem .85rem;
|
||||
margin-bottom: .55rem;
|
||||
color: inherit;
|
||||
transition: border-color .2s, box-shadow .2s;
|
||||
}
|
||||
|
||||
.records-trade-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.records-trade-head {
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
|
||||
.records-trade-title {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: .3rem .4rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.records-trade-code {
|
||||
font-size: .84rem;
|
||||
}
|
||||
|
||||
.records-verified-badge {
|
||||
font-size: .62rem;
|
||||
}
|
||||
|
||||
.records-trade-summary {
|
||||
font-size: .78rem;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.records-trade-actions {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: .3rem;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.records-trade-verify-form {
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.records-trade-actions .btn-link,
|
||||
.records-trade-actions a,
|
||||
.records-trade-actions button {
|
||||
font-size: .72rem;
|
||||
padding: .3rem .5rem;
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.records-trade-actions .btn-link {
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.records-trade-phone-foot {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: .35rem;
|
||||
}
|
||||
|
||||
html:is([data-mobile="1"], .layout-phone) .records-trade-row,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-trade-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
html:is([data-mobile="1"], .layout-phone) .records-trade-row:hover,
|
||||
html:is([data-layout="phone"], .layout-phone) .records-trade-row:hover {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 1px rgba(56, 189, 248, .2);
|
||||
}
|
||||
|
||||
/* 平板横屏:单行 + 右侧操作 */
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: .5rem .65rem;
|
||||
padding: .5rem .75rem;
|
||||
padding: .5rem .65rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-head,
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-meta,
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-foot {
|
||||
display: inline-flex;
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-main {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
gap: .35rem;
|
||||
gap: .55rem .75rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-head {
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-head {
|
||||
margin-bottom: 0;
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-symbol {
|
||||
font-size: .84rem;
|
||||
max-width: 7.5rem;
|
||||
max-width: 6.5rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-meta {
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-summary {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
flex-wrap: nowrap;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: .7rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-size: .76rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-meta .badge {
|
||||
flex-shrink: 0;
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-actions {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-item-foot {
|
||||
flex: 0 0 auto;
|
||||
margin-left: auto;
|
||||
justify-content: flex-end;
|
||||
gap: .45rem;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-pnl {
|
||||
font-size: .82rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-chevron {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-mobile-pnl-lbl {
|
||||
html:is([data-layout="tablet"], .layout-tablet) .records-trade-phone-foot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+17
-11
@@ -12,10 +12,9 @@
|
||||
return String(v).replace('T', ' ').slice(0, 16);
|
||||
}
|
||||
|
||||
function pnlClass(v) {
|
||||
var n = parseFloat(v);
|
||||
if (isNaN(n) || n === 0) return 'is-flat';
|
||||
return n > 0 ? 'is-profit' : 'is-loss';
|
||||
function isTabletLayout() {
|
||||
var root = document.documentElement;
|
||||
return root.dataset.layout === 'tablet' || root.classList.contains('layout-tablet');
|
||||
}
|
||||
|
||||
function showTradeModal(data) {
|
||||
@@ -29,6 +28,7 @@
|
||||
{ label: '类型', value: esc(data.monitor_type) + ' · ' + esc(data.source), wide: false },
|
||||
{ label: '方向', value: esc(data.direction), wide: false },
|
||||
{ label: '成交价', value: esc(data.entry_price), wide: false },
|
||||
{ label: '平仓价', value: esc(data.close_price), wide: false },
|
||||
{ label: '手数', value: esc(data.lots), wide: false },
|
||||
{ label: '止损', value: esc(data.stop_loss), wide: false },
|
||||
{ label: '止盈', value: esc(data.take_profit), wide: false },
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
html += '<div class="records-detail-actions">';
|
||||
if (data.fill_review_url) {
|
||||
html += '<a href="' + data.fill_review_url + '" class="btn-fill">填入复盘</a>';
|
||||
html += '<a href="' + data.fill_review_url + '" class="btn-fill">复盘</a>';
|
||||
}
|
||||
if (data.del_url) {
|
||||
html += '<a href="' + data.del_url + '" class="btn-del" onclick="return confirm(\'删除?\')">删除</a>';
|
||||
@@ -76,12 +76,18 @@
|
||||
mask.addEventListener('click', function (e) {
|
||||
if (e.target === mask) mask.classList.remove('show');
|
||||
});
|
||||
document.querySelectorAll('.records-trade-item').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
try {
|
||||
showTradeModal(JSON.parse(btn.getAttribute('data-trade')));
|
||||
} catch (err) { /* ignore */ }
|
||||
});
|
||||
|
||||
var list = document.getElementById('records-trade-mobile');
|
||||
if (!list) return;
|
||||
|
||||
list.addEventListener('click', function (e) {
|
||||
if (e.target.closest('.records-trade-actions')) return;
|
||||
var row = e.target.closest('.records-trade-row');
|
||||
if (!row) return;
|
||||
if (isTabletLayout() && !e.target.closest('.records-trade-detail-btn')) return;
|
||||
try {
|
||||
showTradeModal(JSON.parse(row.getAttribute('data-trade')));
|
||||
} catch (err) { /* ignore */ }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+45
-18
@@ -30,13 +30,17 @@
|
||||
</label>
|
||||
<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='{{ {
|
||||
{% set trade_pnl = t.pnl_net if t.pnl_net is not none else t.pnl %}
|
||||
{% set trade_px = t.close_price if t.close_price else t.entry_price %}
|
||||
{% set pnl_cls = 'is-profit' if trade_pnl and trade_pnl > 0 else ('is-loss' if trade_pnl and trade_pnl < 0 else 'is-flat') %}
|
||||
<div class="records-trade-row" data-trade-id="{{ t.id }}" 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,
|
||||
"close_price": t.close_price,
|
||||
"stop_loss": t.stop_loss,
|
||||
"take_profit": t.take_profit,
|
||||
"lots": t.lots,
|
||||
@@ -52,28 +56,51 @@
|
||||
"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)
|
||||
"del_url": url_for("del_trade", tid=t.id),
|
||||
"verify_url": url_for("update_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 class="records-trade-main">
|
||||
<div class="records-trade-head">
|
||||
<span class="records-trade-title">
|
||||
<span class="records-mobile-symbol">{{ t.symbol_name or t.symbol }}</span>
|
||||
{% if t.symbol and (t.symbol_name or '')|lower != (t.symbol or '')|lower %}
|
||||
<span class="text-accent records-trade-code">{{ t.symbol }}</span>
|
||||
{% endif %}
|
||||
<span class="badge dir">{{ '做多' if t.direction == 'long' else '做空' }}</span>
|
||||
{% if t.verified %}<span class="badge active records-verified-badge">已核对</span>{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="records-trade-summary">
|
||||
{{ (t.lots or 0)|int }}手 平仓 {{ trade_px if trade_px is not none else '-' }}
|
||||
盈亏 <span class="records-mobile-pnl {{ pnl_cls }}">{{ trade_pnl if trade_pnl is not none else '-' }}</span>
|
||||
</div>
|
||||
</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 class="records-trade-actions">
|
||||
<button type="button" class="btn-link records-trade-detail-btn">详情</button>
|
||||
<a href="{{ url_for('fill_review_from_trade', tid=t.id) }}" class="btn-fill">复盘</a>
|
||||
<form method="post" action="{{ url_for('update_trade', tid=t.id) }}" class="records-trade-verify-form">
|
||||
<input type="hidden" name="symbol_name" value="{{ t.symbol_name or t.symbol }}">
|
||||
<input type="hidden" name="monitor_type" value="{{ t.monitor_type }}">
|
||||
<input type="hidden" name="direction" value="{{ t.direction }}">
|
||||
<input type="hidden" name="entry_price" value="{{ t.entry_price }}">
|
||||
<input type="hidden" name="stop_loss" value="{{ t.stop_loss }}">
|
||||
<input type="hidden" name="take_profit" value="{{ t.take_profit }}">
|
||||
<input type="hidden" name="close_price" value="{{ t.close_price or '' }}">
|
||||
<input type="hidden" name="lots" value="{{ t.lots }}">
|
||||
<input type="hidden" name="margin" value="{{ t.margin or '' }}">
|
||||
<input type="hidden" name="holding_minutes" value="{{ t.holding_minutes or 0 }}">
|
||||
<input type="hidden" name="open_time" value="{{ t.open_time or '' }}">
|
||||
<input type="hidden" name="close_time" value="{{ t.close_time or '' }}">
|
||||
<input type="hidden" name="pnl" value="{{ t.pnl or '' }}">
|
||||
<input type="hidden" name="result" value="{{ t.result }}">
|
||||
<button type="submit" class="btn-verify" {% if t.verified %}disabled{% endif %}>{% if t.verified %}已核对{% else %}核对{% endif %}</button>
|
||||
</form>
|
||||
<a href="{{ url_for('del_trade', tid=t.id) }}" class="btn-del" onclick="return confirm('删除?')">删除</a>
|
||||
</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') }}">
|
||||
<span class="records-mobile-pnl-lbl">净盈亏 </span>{{ t.pnl_net if t.pnl_net is not none else '-' }}
|
||||
</span>
|
||||
<div class="records-trade-phone-foot">
|
||||
<span class="records-mobile-chevron">详情 ›</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="records-mobile-empty">暂无交易记录</p>
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user