移除全部合约同步按钮,改为单合约后台同步带进度条

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 13:53:44 +08:00
parent b74dccd805
commit ca98967af0
3 changed files with 135 additions and 153 deletions
+44 -65
View File
@@ -29,26 +29,17 @@
{# ═══════════════════ Tab: 数据同步 ═══════════════════ #}
<div class="tab-panel{% if tab == 'sync' %} active{% endif %}" id="tab-sync">
<div style="display:flex;align-items:center;gap:12px;margin-bottom:20px;padding:14px 18px;background:var(--surface);border:1px solid var(--border);border-radius:10px;">
<span style="font-size:0.85rem;color:var(--sub);">全部合约</span>
<form method="post" action="/admin/sync" style="display:inline;">
<button type="submit" class="btn btn-primary" style="font-size:0.82rem;padding:6px 16px;">同步行情</button>
</form>
<button id="btn-sync-pos" class="btn btn-primary" style="font-size:0.82rem;padding:6px 16px;background:var(--success);" onclick="startPosSync()">同步持仓</button>
{% if request.query_params.get('synced') %}
<span style="font-size:0.82rem;color:var(--success-fg);">✓ 行情 {{ request.query_params.synced }} 条</span>
{% endif %}
<span id="sync-pos-msg" style="font-size:0.82rem;color:var(--sub);"></span>
<span style="font-size:0.78rem;color:var(--sub);margin-left:auto;">{{ total_contracts }} 个合约</span>
<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px;">
<span style="font-size:0.78rem;color:var(--sub);">共 {{ total_contracts }} 个合约</span>
</div>
<div id="pos-progress" style="display:none;margin-bottom:20px;padding:14px 18px;background:var(--surface);border:1px solid var(--border);border-radius:10px;">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;">
<span id="pos-progress-label" style="font-size:0.82rem;color:var(--fg);">正在同步...</span>
<span id="pos-progress-pct" style="font-size:0.82rem;color:var(--sub);margin-left:auto;"></span>
<div id="sync-progress" style="display:none;margin-bottom:18px;padding:12px 16px;background:var(--surface);border:1px solid var(--border);border-radius:8px;">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:6px;">
<span id="sync-progress-label" style="font-size:0.82rem;color:var(--fg);">正在同步...</span>
<span id="sync-progress-pct" style="font-size:0.8rem;color:var(--sub);margin-left:auto;"></span>
</div>
<div style="width:100%;height:6px;background:var(--border);border-radius:3px;overflow:hidden;">
<div id="pos-progress-bar" style="width:0%;height:100%;background:var(--accent);border-radius:3px;transition:width .3s;"></div>
<div style="width:100%;height:5px;background:var(--border);border-radius:3px;overflow:hidden;">
<div id="sync-progress-bar" style="width:0%;height:100%;background:var(--accent);border-radius:3px;transition:width .3s;"></div>
</div>
</div>
@@ -63,7 +54,7 @@
<span style="font-size:0.78rem;color:var(--sub);">{{ p.exchange }}</span>
<span style="font-size:0.78rem;color:var(--sub);margin-left:8px;">{{ p.contracts|length }} 合约</span>
<form method="post" action="/admin/sync/product/{{ p.id }}" style="display:inline;margin-left:auto;" onclick="event.stopPropagation()">
<button type="submit" class="btn" style="font-size:0.78rem;padding:4px 14px;background:var(--accent);color:#fff;border-radius:5px;">同步该品种</button>
<button type="submit" class="btn" style="font-size:0.78rem;padding:4px 14px;background:var(--accent);color:#fff;border-radius:5px;">同步行情</button>
</form>
</div>
<div class="product-body" style="display:none;">
@@ -78,9 +69,8 @@
</td>
<td style="text-align:center;padding:6px 14px;">
<a href="/contracts/{{ c.code }}" style="color:var(--accent);text-decoration:none;font-size:0.82rem;">查看</a>
<form method="post" action="/admin/sync/{{ c.code }}" style="display:inline;margin-left:8px;">
<button style="background:none;border:none;color:var(--accent);cursor:pointer;font-size:0.82rem;">同步</button>
</form>
<button style="background:none;border:none;color:var(--accent);cursor:pointer;font-size:0.82rem;margin-left:4px;" onclick="syncBars('{{ c.code }}')">↻ 行情</button>
<button style="background:none;border:none;color:var(--success);cursor:pointer;font-size:0.82rem;" onclick="syncPositions('{{ c.code }}')">持仓</button>
</td>
</tr>
{% endfor %}
@@ -202,64 +192,53 @@
</div>
<script>
var posSyncTimer = null;
var syncTimer = null;
function startPosSync() {
var btn = document.getElementById('btn-sync-pos');
btn.disabled = true;
btn.textContent = '发起中...';
document.getElementById('sync-pos-msg').textContent = '';
function showProgress() {
document.getElementById('sync-progress').style.display = 'block';
document.getElementById('sync-progress-bar').style.width = '0%';
document.getElementById('sync-progress-pct').textContent = '';
document.getElementById('sync-progress-label').textContent = '正在同步...';
}
fetch('/admin/sync-positions', { method: 'POST' })
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.error) {
document.getElementById('sync-pos-msg').textContent = '⚠ ' + data.error;
btn.disabled = false;
btn.textContent = '同步持仓';
return;
}
document.getElementById('pos-progress').style.display = 'block';
btn.textContent = '同步中...';
posSyncTimer = setInterval(pollProgress, 800);
});
function hideProgress() {
clearInterval(syncTimer);
document.getElementById('sync-progress').style.display = 'none';
}
function pollProgress() {
fetch('/admin/sync-status')
.then(function(r) { return r.json(); })
.then(function(data) {
var done = data.contract_done;
var total = data.contract_total;
var dDone = data.date_done;
var dTotal = data.date_total;
var pct = 0;
var pct = data.total > 0 ? Math.round(data.done / data.total * 100) : 0;
document.getElementById('sync-progress-bar').style.width = pct + '%';
document.getElementById('sync-progress-pct').textContent = pct + '%';
document.getElementById('sync-progress-label').textContent = data.label;
if (data.finished) {
pct = 100;
clearInterval(posSyncTimer);
document.getElementById('pos-progress-pct').textContent = '100%';
document.getElementById('pos-progress-label').textContent =
'完成:' + total + ' 个合约,共同步 ' + data.rows + ' 条持仓数据';
document.getElementById('sync-pos-msg').textContent = '✓ 已同步 ' + data.rows + ' 条';
var btn = document.getElementById('btn-sync-pos');
btn.disabled = false;
btn.textContent = '同步持仓';
} else if (total > 0) {
// Weight: contracts account for most of the bar, dates for fine-grained within current contract
pct = Math.round((done + (dTotal > 0 ? dDone / dTotal : 0)) / total * 100);
document.getElementById('pos-progress-pct').textContent = pct + '%';
var label = '合约 ' + (done + 1) + '/' + total + '' + data.contract;
if (dTotal > 0) {
label += '' + dDone + '/' + dTotal + ' 天)';
}
document.getElementById('pos-progress-label').textContent = label;
clearInterval(syncTimer);
document.getElementById('sync-progress-bar').style.width = '100%';
document.getElementById('sync-progress-pct').textContent = '100%';
document.getElementById('sync-progress-label').textContent = data.label + ' 完成';
document.getElementById('sync-progress-pct').textContent = '';
}
document.getElementById('pos-progress-bar').style.width = pct + '%';
});
}
function startSync(url) {
if (syncTimer) { clearInterval(syncTimer); }
showProgress();
fetch(url, { method: 'POST' })
.then(function(r) { return r.json(); })
.then(function(data) {
if (!data.ok) { hideProgress(); return; }
syncTimer = setInterval(pollProgress, 600);
});
}
function syncBars(code) { startSync('/admin/sync/' + code + '/bg'); }
function syncPositions(code) { startSync('/admin/sync-positions/' + code + '/bg'); }
function switchTab(name) {
document.querySelectorAll('.tab-btn').forEach(function(b) { b.classList.remove('active'); });
document.querySelectorAll('.tab-panel').forEach(function(p) { p.classList.remove('active'); });