55 lines
6.6 KiB
HTML
55 lines
6.6 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}AlphaX Agent — 数据导出{% endblock %}
|
||
{% block extra_head_css %}
|
||
<style>
|
||
.shell{width:min(100% - 40px,1120px);margin:0 auto;padding:28px 0 56px}.hero{position:relative;overflow:hidden;border:1px solid var(--hairline-soft);border-radius:24px;background:linear-gradient(135deg,#0f172a 0%,#1f3a5f 52%,#0f766e 100%);padding:26px;color:white;box-shadow:0 24px 70px rgba(15,23,42,.18)}.hero:after{content:"";position:absolute;right:-80px;top:-80px;width:260px;height:260px;border-radius:999px;background:rgba(255,255,255,.14);filter:blur(4px)}.hero h1{position:relative;font-size:30px;font-weight:950;letter-spacing:-.9px;margin:0}.hero p{position:relative;margin:8px 0 0;max-width:760px;color:rgba(255,255,255,.78);line-height:1.65;font-size:13px}.grid{display:grid;grid-template-columns:1fr 360px;gap:14px;margin-top:14px}.panel{border:1px solid var(--hairline-soft);background:var(--canvas);border-radius:var(--radius-md);padding:16px}.panel-title{font-size:15px;font-weight:950;color:var(--ink);margin-bottom:8px}.hint{color:var(--stone);font-size:12px;line-height:1.6}.quick{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:14px}.choice{border:1px solid var(--hairline-soft);background:var(--surface);border-radius:16px;padding:14px;text-align:left;cursor:pointer;transition:.15s}.choice:hover,.choice.active{border-color:rgba(66,98,255,.35);background:rgba(66,98,255,.055);transform:translateY(-1px)}.choice b{display:block;font-size:18px;color:var(--ink);font-weight:950}.choice span{display:block;margin-top:4px;color:var(--stone);font-size:11px;font-weight:850}.custom{display:flex;gap:8px;align-items:center;margin-top:14px}.input{height:40px;border:1px solid var(--hairline-strong);border-radius:12px;background:var(--canvas);padding:0 12px;color:var(--ink);font-weight:850;width:110px}.btn{height:42px;border:0;border-radius:999px;background:var(--ink);color:var(--canvas);padding:0 18px;font-weight:950;cursor:pointer}.btn:disabled{opacity:.55;cursor:default}.status{margin-top:12px;border:1px solid rgba(66,98,255,.16);background:rgba(66,98,255,.05);border-radius:14px;padding:11px;color:var(--slate);font-size:12px;line-height:1.55}.list{display:grid;gap:8px;margin-top:10px}.item{display:flex;justify-content:space-between;gap:12px;border-bottom:1px solid var(--hairline-soft);padding:9px 0;font-size:12px}.item:last-child{border-bottom:0}.item b{color:var(--ink)}.item span{color:var(--stone);text-align:right}@media(max-width:900px){.grid{grid-template-columns:1fr}.quick{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:560px){.shell{width:min(100% - 24px,1120px)}.quick{grid-template-columns:1fr}.custom{align-items:stretch;flex-direction:column}.input{width:100%}}
|
||
</style>
|
||
{% endblock %}
|
||
{% block content %}
|
||
<div class="shell">
|
||
<section class="hero">
|
||
<h1>数据导出</h1>
|
||
<p>把线上最近一段时间的链路、推荐、挂单、成交、复盘、推送和配置快照打包下载。下载后的 ZIP 可以直接拿来做本地分析、策略复盘和功能优化。</p>
|
||
</section>
|
||
|
||
<div class="grid">
|
||
<section class="panel">
|
||
<div class="panel-title">选择导出窗口</div>
|
||
<div class="hint">推荐先导出 24 小时用于快速排查;做策略复盘时导出 7 天或 30 天。导出包是 ZIP,里面按表拆分 JSON 文件。</div>
|
||
<div class="quick" id="quickChoices">
|
||
<button class="choice active" type="button" data-hours="24" onclick="chooseHours(24,this)"><b>24 小时</b><span>最近链路排查</span></button>
|
||
<button class="choice" type="button" data-hours="72" onclick="chooseHours(72,this)"><b>3 天</b><span>短周期异常</span></button>
|
||
<button class="choice" type="button" data-hours="168" onclick="chooseHours(168,this)"><b>7 天</b><span>策略小复盘</span></button>
|
||
<button class="choice" type="button" data-hours="720" onclick="chooseHours(720,this)"><b>30 天</b><span>完整表现分析</span></button>
|
||
</div>
|
||
<div class="custom">
|
||
<input class="input" id="customDays" type="number" min="1" max="90" value="1">
|
||
<span class="hint">天</span>
|
||
<button class="btn" id="downloadBtn" type="button" onclick="downloadExport()">下载导出包</button>
|
||
</div>
|
||
<div class="status" id="exportStatus">当前选择:最近 24 小时。</div>
|
||
</section>
|
||
|
||
<aside class="panel">
|
||
<div class="panel-title">导出内容</div>
|
||
<div class="list">
|
||
<div class="item"><b>推荐链路</b><span>recommendation / screening_log / cron_run_log</span></div>
|
||
<div class="item"><b>交易账本</b><span>paper_orders / paper_trades / events</span></div>
|
||
<div class="item"><b>复盘迭代</b><span>review / missed / strategy rules</span></div>
|
||
<div class="item"><b>证据源</b><span>舆情 / 链上 / AI 记录</span></div>
|
||
<div class="item"><b>运行配置</b><span>策略与系统配置快照</span></div>
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
{% block extra_script %}
|
||
<script>
|
||
var selectedHours=24;
|
||
function $(id){return document.getElementById(id)}
|
||
function chooseHours(hours,el){selectedHours=hours;Array.prototype.forEach.call(document.querySelectorAll('.choice'),function(x){x.classList.remove('active')});if(el)el.classList.add('active');$('customDays').value=Math.max(1,Math.round(hours/24));$('exportStatus').textContent='当前选择:最近 '+labelHours(hours)+'。'}
|
||
function labelHours(hours){if(hours===24)return'24 小时';if(hours%24===0)return (hours/24)+' 天';return hours+' 小时'}
|
||
async function downloadExport(){var days=Number($('customDays').value||1);if(days>0)selectedHours=Math.max(1,Math.min(2160,Math.round(days*24)));var btn=$('downloadBtn');btn.disabled=true;btn.textContent='打包中...';$('exportStatus').textContent='正在生成最近 '+labelHours(selectedHours)+' 的导出包,请稍等...';try{var resp=await fetch('/api/admin/data-export?hours='+encodeURIComponent(selectedHours));if(!resp.ok){var t=await resp.text();throw new Error(t||'导出失败')}var blob=await resp.blob();var name='alphax_export_'+selectedHours+'h.zip';var cd=resp.headers.get('content-disposition')||'';var m=cd.match(/filename="([^"]+)"/);if(m)name=m[1];var url=URL.createObjectURL(blob);var a=document.createElement('a');a.href=url;a.download=name;document.body.appendChild(a);a.click();a.remove();URL.revokeObjectURL(url);$('exportStatus').textContent='导出完成:'+name+'。下载后可以把 ZIP 给我做本地分析。'}catch(e){$('exportStatus').textContent='导出失败:'+e.message}finally{btn.disabled=false;btn.textContent='下载导出包'}}
|
||
</script>
|
||
{% endblock %}
|