首次上传

This commit is contained in:
dekun
2026-05-16 22:25:48 +08:00
commit 2b8f902548
88 changed files with 16386 additions and 0 deletions
@@ -0,0 +1,463 @@
<!DOCTYPE html>
<!-- 勿用「文件」方式双击打开本模板:请启动服务后访问 http://127.0.0.1:8090/dashboard(端口见 config.yaml -->
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<meta name="color-scheme" content="dark" />
<title>GATE // EXECUTOR</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;700&family=Share+Tech+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/static/style.css?v={{ asset_version }}" />
<link rel="stylesheet" href="/static/theme-matrix-terminal.css?v={{ asset_version }}" />
</head>
<body class="exec-shell exec-dashboard exec-theme-matrix">
<div
id="exec-local-file-overlay"
style="display:none;position:fixed;inset:0;z-index:2147483647;background:#050508;color:#e4e4e7;font-family:system-ui,sans-serif;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:32px;gap:14px;"
>
<p style="margin:0;font-size:1.05rem;font-weight:600;">检测到正在用本地文件(file://)打开</p>
<p style="margin:0;font-size:0.9rem;opacity:0.88;max-width:460px;line-height:1.65;">
此方式不会经过 FastAPI,模板变量不会渲染,<code style="background:#1a1a22;padding:2px 8px;border-radius:6px;">/static/style.css</code>
也无法加载,所以页面是白底「裸 HTML」。
</p>
<p style="margin:0;font-size:0.9rem;line-height:1.65;">
请在项目根目录执行 <code style="background:#1a1a22;padding:2px 8px;border-radius:6px;">python run.py</code>(或 PM2),然后访问:<br />
<strong style="color:#fafafa;font-size:1rem;">http://127.0.0.1:8090/dashboard</strong><br />
<span style="opacity:0.75;font-size:0.82rem;">端口以 config.yaml 里 app.port 为准</span>
</p>
</div>
<script>
(function () {
if (location.protocol === "file:") {
var o = document.getElementById("exec-local-file-overlay");
if (o) o.style.display = "flex";
}
})();
</script>
<div class="exec-ambient" aria-hidden="true"></div>
<div class="exec-noise" aria-hidden="true"></div>
<div class="exec-grid-faint" aria-hidden="true"></div>
<header class="exec-header exec-header--terminal">
<div class="exec-terminal-bar">
<span class="exec-tx-chip exec-tx-chip--live"><span class="exec-tx-dot" aria-hidden="true"></span>LINK ONLINE</span>
<span class="exec-tx-chip">CYCLE <strong>OK</strong></span>
<span class="exec-tx-chip">CHANNEL <strong id="execTxChannel"></strong></span>
<span class="exec-tx-chip exec-tx-chip--time">SYNC <span class="exec-tx-mono" id="execClock">--:--:--</span></span>
</div>
<div class="exec-terminal-head">
<div class="exec-terminal-logo" aria-hidden="true">GE</div>
<div class="exec-terminal-center">
<h1 class="exec-title-terminal">
<span class="exec-tt-part">GATE</span>
<span class="exec-title-slash">//</span>
<span class="exec-radar" aria-hidden="true">
<span class="exec-radar__ring"></span>
<span class="exec-radar__sweep"></span>
<span class="exec-radar__blip"></span>
</span>
<span class="exec-title-slash">//</span>
<span class="exec-tt-part">EXECUTOR</span>
</h1>
<p class="exec-tagline-terminal">Gate USDT PERP · SCHEME-A · MATRIX SCAN ISOLATED</p>
</div>
<div class="exec-terminal-actions">
<span class="exec-tx-chip">OP <strong id="execUser">{{ username }}</strong></span>
<a class="exec-btn exec-btn--sm" href="/logout">LOGOUT</a>
</div>
</div>
</header>
<main class="exec-main exec-main--tabbed">
<nav class="exec-tabs" id="execTabs" role="tablist" aria-label="面板分区">
<button type="button" class="exec-tab exec-tab--active" role="tab" id="tab-overview" data-exec-tab="overview" aria-selected="true">概览</button>
<button type="button" class="exec-tab" role="tab" id="tab-positions" data-exec-tab="positions" aria-selected="false">持仓与计划</button>
<button type="button" class="exec-tab" role="tab" id="tab-history" data-exec-tab="history" aria-selected="false">成交与委托</button>
<button type="button" class="exec-tab" role="tab" id="tab-stats" data-exec-tab="stats" aria-selected="false">统计</button>
<button type="button" class="exec-tab" role="tab" id="tab-signals" data-exec-tab="signals" aria-selected="false">信号流</button>
</nav>
<div class="exec-tab-panels">
<div class="exec-tab-panel exec-tab-panel--active" data-exec-panel="overview" role="tabpanel" aria-labelledby="tab-overview">
<p class="exec-section-label">Overview</p>
<div class="exec-module-row exec-module-row--3">
<!-- 模块:运行态 -->
<section class="exec-module" aria-labelledby="mod-runtime-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-runtime-title">运行态</h2>
<span class="exec-module-meta">Runtime</span>
</div>
<div class="exec-module-body">
<div class="exec-metric-grid">
<div class="exec-metric">
<span class="exec-metric-label">模式</span>
<div class="exec-metric-value" id="stDryRunWrap"></div>
</div>
<div class="exec-metric">
<span class="exec-metric-label">Gate 密钥</span>
<div class="exec-metric-value" id="stKeysWrap"></div>
</div>
<div class="exec-metric">
<span class="exec-metric-label">占位仓位</span>
<span class="exec-metric-value exec-metric-value--mono" id="stSlots"></span>
</div>
<div class="exec-metric">
<span class="exec-metric-label">单笔风险 / 方案</span>
<span class="exec-metric-value exec-metric-value--mono"><span id="stRisk"></span> · <span id="stScheme"></span></span>
</div>
</div>
</div>
</section>
<!-- 模块:网络 -->
<section class="exec-module" aria-labelledby="mod-net-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-net-title">网络与代理</h2>
<span class="exec-module-meta">Egress</span>
</div>
<div class="exec-module-body">
<div class="exec-metric-grid">
<div class="exec-metric">
<span class="exec-metric-label">配置启用</span>
<div class="exec-metric-value" id="pxEnabledWrap"></div>
</div>
<div class="exec-metric">
<span class="exec-metric-label">实际走代理</span>
<div class="exec-metric-value" id="pxEffectiveWrap"></div>
</div>
</div>
<div class="exec-metric" style="margin-top: 12px">
<span class="exec-metric-label">代理地址</span>
<span class="exec-metric-value exec-metric-value--mono" id="pxUrl"></span>
</div>
<p class="exec-prose"><code>onchain_scout_gate</code><code>proxy</code> 配置一致;访问 Gate 私有 API 时使用 <code>httpx_client_kwargs</code><code>app/proxy_util.py</code>)。</p>
</div>
</section>
<!-- 模块:风险摘要 -->
<section class="exec-module" aria-labelledby="mod-risk-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-risk-title">风险参数</h2>
<span class="exec-module-meta">Risk</span>
</div>
<div class="exec-module-body">
<div class="exec-metric">
<span class="exec-metric-label">以损订仓(目标)</span>
<span class="exec-metric-value exec-metric-value--mono" id="stRiskLarge"></span>
</div>
<div class="exec-metric" style="margin-top: 12px">
<span class="exec-metric-label">最大同时标的</span>
<span class="exec-metric-value exec-metric-value--mono" id="stMaxPos"></span>
</div>
<p class="exec-prose"><code>gate.dry_run: false</code> 且配置 API 密钥时,按上述参数与止损距离计算张数并下市价单 + 计划止盈/止损;<code>dry_run: true</code> 时仅校验占位与日志。</p>
</div>
</section>
</div>
<p class="exec-section-label">Account</p>
<section class="exec-module exec-module--wide" aria-labelledby="mod-acct-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-acct-title">合约账户</h2>
<span class="exec-module-meta">与 Overview 同步刷新(联调请用 curl,见部署/使用说明)</span>
</div>
<div class="exec-module-body">
<div class="exec-metric-grid">
<div class="exec-metric">
<span class="exec-metric-label">权益 total</span>
<span class="exec-metric-value exec-metric-value--mono" id="faTotal"></span>
</div>
<div class="exec-metric">
<span class="exec-metric-label">可用 available</span>
<span class="exec-metric-value exec-metric-value--mono" id="faAvail"></span>
</div>
<div class="exec-metric">
<span class="exec-metric-label">未实现盈亏</span>
<span class="exec-metric-value exec-metric-value--mono" id="faUpnl"></span>
</div>
<div class="exec-metric">
<span class="exec-metric-label">币种</span>
<span class="exec-metric-value" id="faCur"></span>
</div>
</div>
<p class="exec-prose" id="faErr" style="display:none;color:#fca5a5;margin-top:12px"></p>
</div>
</section>
</div>
<div class="exec-tab-panel" data-exec-panel="positions" role="tabpanel" aria-labelledby="tab-positions">
<p class="exec-section-label">Positions</p>
<section class="exec-module exec-module--wide" aria-labelledby="mod-pos-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-pos-title">当前持仓(Gate</h2>
<span class="exec-module-meta">与计划委托同一轮询 · 便于对账</span>
</div>
<div class="exec-module-body">
<div class="exec-sig-rr-toolbar" style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:14px">
<label class="exec-sig-export-label"><input type="checkbox" id="beGlobalEnable" checked /> 全局移动保本(达 1R 拉至保本+0.2%)</label>
<button type="button" class="exec-btn exec-btn--sm" id="beGlobalSave">保存全局</button>
<span class="exec-muted" id="beGlobalMsg" role="status" aria-live="polite"></span>
</div>
<p class="exec-prose" id="posErr" style="display:none;color:#fca5a5;margin-bottom:12px"></p>
<p class="exec-prose" id="posPlanHint" style="display:none;margin:0 0 12px;font-size:0.88rem;color:#fbbf24;line-height:1.55"></p>
<div class="exec-table-scroll">
<table class="exec-table" id="posTable">
<thead>
<tr>
<th>合约</th>
<th>张数</th>
<th>开仓价</th>
<th>标记价</th>
<th>未实现盈亏</th>
<th>杠杆</th>
<th>open 计划单</th>
<th>移动保本</th>
<th>保本状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="posBody">
<tr><td colspan="10" class="exec-muted">加载中…</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<div id="posPlanModal" class="exec-modal" aria-hidden="true">
<div class="exec-modal__backdrop" id="posPlanModalBackdrop"></div>
<div class="exec-modal__card" role="dialog" aria-labelledby="posPlanModalTitle">
<h3 class="exec-modal__title" id="posPlanModalTitle">增加计划委托(市价全平)</h3>
<p class="exec-prose" style="margin:0 0 12px;font-size:0.85rem;opacity:0.88">合约 <span class="exec-mono" id="posPlanModalContract"></span> · 触发后市价 IOC、reduce_only 全平(与信号止盈止损同一套 <code>price_orders</code>)。</p>
<div class="exec-field" style="margin-bottom:12px">
<label class="exec-label" for="posPlanTrigger">触发价</label>
<input class="exec-input" id="posPlanTrigger" type="text" inputmode="decimal" placeholder="如 95000.5" autocomplete="off" />
</div>
<div class="exec-field" style="margin-bottom:16px">
<label class="exec-label" for="posPlanRule">触发规则</label>
<select class="exec-input" id="posPlanRule" style="cursor:pointer;width:100%">
<option value="1">最新价 &gt;= 触发价(rule=1</option>
<option value="2">最新价 &lt;= 触发价(rule=2</option>
</select>
</div>
<p class="exec-prose" id="posPlanModalErr" style="display:none;color:#fca5a5;margin-bottom:12px"></p>
<div style="display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap">
<button type="button" class="exec-btn" id="posPlanModalCancel">取消</button>
<button type="button" class="exec-btn exec-btn--primary" id="posPlanModalSubmit">提交</button>
</div>
</div>
</div>
<p class="exec-section-label">Plan orders</p>
<section class="exec-module exec-module--wide" aria-labelledby="mod-plan-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-plan-title">计划委托(price_orders</h2>
<span class="exec-module-meta">与概览同步轮询 · 可手动撤单</span>
</div>
<div class="exec-module-body">
<p class="exec-prose" id="planHint" style="margin:0 0 12px;font-size:0.88rem;opacity:0.9">
与上方<strong>持仓表按合约对账</strong>:有仓但「open 计划单」为 0 时多为止盈止损已触发/已撤或 OCO 清理延迟;无仓但有计划单时可能为挂单待触发或他端下的条件单。
</p>
<p class="exec-prose" id="planErr" style="display:none;color:#fca5a5;margin-bottom:12px"></p>
<div class="exec-table-scroll">
<table class="exec-table" id="planTable">
<thead>
<tr>
<th>合约</th>
<th>状态</th>
<th>触发价</th>
<th>rule</th>
<th>张数</th>
<th>类型</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="planBody">
<tr><td colspan="8" class="exec-muted">加载中…</td></tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
<div class="exec-tab-panel" data-exec-panel="history" role="tabpanel" aria-labelledby="tab-history">
<p class="exec-section-label">Gate history</p>
<section class="exec-module exec-module--wide" aria-labelledby="mod-gh-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-gh-title">成交与委托(Gate 官方接口)</h2>
<span class="exec-module-meta">查询 / 下载 CSV · 与信号流无关</span>
</div>
<div class="exec-module-body">
<p class="exec-prose" style="margin:0 0 12px;font-size:0.88rem;opacity:0.9">
数据以 <strong>Gate 合约私有 API</strong> 为准:<code>my_trades_timerange</code>(成交)、<code>orders</code>(委托)。
未填「from / to」时按服务端默认最近 7 天(Unix 秒)。导出最多 5000 行(分页拼接)。
</p>
<div class="exec-test-bar" style="margin-bottom:14px;display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end">
<div class="exec-field" style="margin:0;min-width:140px">
<label class="exec-label" for="ghContract">合约(可选)</label>
<input class="exec-input" id="ghContract" type="text" placeholder="留空=全部" autocomplete="off" />
</div>
<div class="exec-field" style="margin:0;min-width:120px">
<label class="exec-label" for="ghFrom">fromUnix 秒)</label>
<input class="exec-input" id="ghFrom" type="text" inputmode="numeric" placeholder="默认 7 天前" autocomplete="off" />
</div>
<div class="exec-field" style="margin:0;min-width:120px">
<label class="exec-label" for="ghTo">toUnix 秒)</label>
<input class="exec-input" id="ghTo" type="text" inputmode="numeric" placeholder="默认此刻" autocomplete="off" />
</div>
<button type="button" class="exec-btn" id="btnGhTrades">查询成交</button>
<button type="button" class="exec-btn" id="btnGhTradesCsv">下载成交 CSV</button>
<div class="exec-field" style="margin:0;min-width:110px">
<label class="exec-label" for="ghOrdStatus">委托 status</label>
<select class="exec-input" id="ghOrdStatus" style="cursor:pointer">
<option value="finished">finished</option>
<option value="open">open</option>
</select>
</div>
<button type="button" class="exec-btn" id="btnGhOrders">查询委托</button>
<button type="button" class="exec-btn" id="btnGhOrdersCsv">下载委托 CSV</button>
</div>
<p class="exec-prose" id="ghErr" style="display:none;color:#fca5a5;margin-bottom:12px"></p>
<p class="exec-section-label" style="margin-top:4px">成交(最近一页,limit=80</p>
<div class="exec-table-scroll">
<table class="exec-table" id="ghTradesTable">
<thead>
<tr>
<th>时间</th>
<th>合约</th>
<th>张数</th>
<th>价格</th>
<th>手续费</th>
<th>角色</th>
<th>trade_id</th>
</tr>
</thead>
<tbody id="ghTradesBody">
<tr><td colspan="7" class="exec-muted">点击「查询成交」</td></tr>
</tbody>
</table>
</div>
<p class="exec-section-label" style="margin-top:18px">委托(最近一页,limit=80</p>
<div class="exec-table-scroll">
<table class="exec-table" id="ghOrdersTable">
<thead>
<tr>
<th>创建</th>
<th>合约</th>
<th>状态</th>
<th>张数</th>
<th>价 / 成交价</th>
<th>id</th>
</tr>
</thead>
<tbody id="ghOrdersBody">
<tr><td colspan="6" class="exec-muted">点击「查询委托」</td></tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
<div class="exec-tab-panel" data-exec-panel="stats" role="tabpanel" aria-labelledby="tab-stats">
<p class="exec-section-label">Formal stats</p>
<section class="exec-module exec-module--wide" aria-labelledby="mod-st-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-st-title">正式统计</h2>
<span class="exec-module-meta">GET /api/stats/summary · 手动刷新</span>
</div>
<div class="exec-module-body">
<p class="exec-prose" style="margin:0 0 12px;font-size:0.88rem;opacity:0.9">
口径:<strong>上海时区</strong>、统计日 <strong>[D 08:00, D+1 08:00)</strong>、自然周 <strong>周一至周日</strong>、自然月 <strong>[1日08:00, 次月1日08:00)</strong>;数据来自 Gate <code>GET /futures/&lt;settle&gt;/position_close</code>(与 App「历史仓位」同类),仅统计 <code>stats.official_start</code> 之后<strong>平仓时间</strong>且能解析 <code>pnl</code> 的记录。详见 <code>docs/使用说明.md</code> §3.6。
</p>
<div class="exec-test-bar" style="margin-bottom:14px;display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end">
<div class="exec-field" style="margin:0;min-width:140px">
<label class="exec-label" for="stContract">合约(可选)</label>
<input class="exec-input" id="stContract" type="text" placeholder="留空=全部" autocomplete="off" />
</div>
<button type="button" class="exec-btn exec-btn--primary" id="btnStatsRefresh">刷新统计</button>
</div>
<p class="exec-prose" id="statsErr" style="display:none;color:#fca5a5;margin-bottom:12px"></p>
<p class="exec-prose" id="statsWarn" style="display:none;color:#fbbf24;margin-bottom:12px;font-size:0.88rem"></p>
<p class="exec-prose exec-muted" id="statsIdle" style="margin:0 0 16px;font-size:0.88rem">尚未加载;请点击「刷新统计」(会请求 Gate 分页拉成交,请勿频繁点击)。</p>
<div class="exec-module-row exec-module-row--3" id="statsCards" style="display:none">
<section class="exec-module" aria-labelledby="st-day-title">
<div class="exec-module-head">
<h3 class="exec-module-title" id="st-day-title" style="font-size:1rem">本统计日</h3>
<span class="exec-module-meta" id="stDayMeta"></span>
</div>
<div class="exec-module-body" id="stDayBody"></div>
</section>
<section class="exec-module" aria-labelledby="st-week-title">
<div class="exec-module-head">
<h3 class="exec-module-title" id="st-week-title" style="font-size:1rem">本周</h3>
<span class="exec-module-meta" id="stWeekMeta"></span>
</div>
<div class="exec-module-body" id="stWeekBody"></div>
</section>
<section class="exec-module" aria-labelledby="st-month-title">
<div class="exec-module-head">
<h3 class="exec-module-title" id="st-month-title" style="font-size:1rem">本月</h3>
<span class="exec-module-meta" id="stMonthMeta"></span>
</div>
<div class="exec-module-body" id="stMonthBody"></div>
</section>
</div>
</div>
</section>
</div>
<div class="exec-tab-panel" data-exec-panel="signals" role="tabpanel" aria-labelledby="tab-signals">
<p class="exec-section-label">Signal stream</p>
<section class="exec-module exec-module--wide" aria-labelledby="mod-sig-title">
<div class="exec-module-head">
<h2 class="exec-module-title" id="mod-sig-title">信号流</h2>
<span class="exec-module-meta">POST /v1/signal</span>
</div>
<div class="exec-module-body">
<div class="exec-table-toolbar">
<p class="exec-table-hint">每次 <code>POST /v1/signal</code> 的处理结果<strong>写入本地 SQLite</strong>,本页「信号流」从该库读取最近记录,<strong>进程重启后仍在</strong>(与当前是否持仓无关)。止盈/止损展示价为按合约 tick 对齐;现价优先 <code>reference_price</code>,否则取推送时行情 last。</p>
<div class="exec-sig-export" aria-label="信号流导出">
<label class="exec-sig-export-label"><input type="checkbox" id="sigExportEnable" /> 允许下载 CSV</label>
<button type="button" class="exec-btn exec-btn--sm" id="sigExportBtn" disabled>下载</button>
</div>
<div class="exec-sig-rr-toolbar" style="display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-top:14px">
<label class="exec-sig-export-label" for="sigMinRrInput">最低盈亏比(无法计算或低于此值则拒单)</label>
<input type="number" class="exec-input" id="sigMinRrInput" min="0.1" max="50" step="0.05" style="width:6.5rem" autocomplete="off" />
<button type="button" class="exec-btn exec-btn--sm" id="sigMinRrSave">保存到服务端</button>
<span class="exec-muted" id="sigMinRrMsg" role="status" aria-live="polite"></span>
</div>
</div>
<p id="sigPersistBanner" class="exec-sig-persist" role="status" aria-live="polite"></p>
<div class="exec-table-scroll">
<table class="exec-table" id="sigTable">
<thead>
<tr>
<th>时间</th>
<th>合约</th>
<th>方向</th>
<th>现价</th>
<th>止盈</th>
<th>止损</th>
<th>盈亏比</th>
<th>结果</th>
</tr>
</thead>
<tbody id="sigBody">
<tr><td colspan="8" class="exec-muted">加载中…</td></tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
</div>
</main>
<script src="/static/exec.js?v={{ asset_version }}"></script>
</body>
</html>
+104
View File
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<!-- 勿双击本地打开:请启动服务后访问 http://127.0.0.1:8090/login -->
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#000000" />
<title>GATE // EXECUTOR · 接入</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;700&family=Share+Tech+Mono&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/static/style.css?v={{ asset_version }}" />
<link rel="stylesheet" href="/static/theme-matrix-terminal.css?v={{ asset_version }}" />
</head>
<body class="exec-shell exec-login-body exec-theme-matrix">
<div
id="exec-local-file-overlay"
style="display:none;position:fixed;inset:0;z-index:2147483647;background:#050508;color:#e4e4e7;font-family:system-ui,sans-serif;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:32px;gap:14px;"
>
<p style="margin:0;font-size:1.05rem;font-weight:600;">请通过运行中的服务打开登录页</p>
<p style="margin:0;font-size:0.9rem;opacity:0.88;max-width:440px;line-height:1.65;">
本地 file:// 打开无法加载 <code style="background:#1a1a22;padding:2px 8px;border-radius:6px;">/static/style.css</code>,因此不是设计稿效果。
</p>
<p style="margin:0;font-size:0.9rem;">
启动后访问:<strong style="color:#fafafa;">http://127.0.0.1:8090/login</strong>
</p>
</div>
<script>
(function () {
if (location.protocol === "file:") {
var o = document.getElementById("exec-local-file-overlay");
if (o) o.style.display = "flex";
}
})();
</script>
<div class="exec-ambient" aria-hidden="true"></div>
<div class="exec-noise" aria-hidden="true"></div>
<div class="exec-grid-faint" aria-hidden="true"></div>
<div class="exec-login-stage">
<div class="exec-login-card">
<div class="exec-login-inner">
<div class="exec-header__brand" style="margin-bottom: 24px">
<div class="exec-mark" aria-hidden="true">GE</div>
<div class="exec-header__text">
<p class="exec-login-kicker">GATE // EXECUTOR</p>
<h1 class="exec-login-title">安全接入</h1>
</div>
</div>
<p class="exec-login-desc">独立执行进程 · 与 MATRIX 扫描解耦 · 未授权禁止访问控制台</p>
<form id="execLoginForm" class="exec-login-form" action="#" method="post">
<div class="exec-field">
<label class="exec-label" for="f-user">操作员</label>
<input class="exec-input" id="f-user" type="text" name="username" required autocomplete="username" />
</div>
<div class="exec-field">
<label class="exec-label" for="f-pass">密码</label>
<input class="exec-input" id="f-pass" type="password" name="password" required autocomplete="current-password" />
</div>
<button type="submit" class="exec-btn exec-btn--primary">进入控制台</button>
</form>
<div class="exec-error" id="execLoginError"></div>
</div>
</div>
</div>
<script>
(function () {
var form = document.getElementById("execLoginForm");
var errEl = document.getElementById("execLoginError");
form.addEventListener("submit", function (e) {
e.preventDefault();
errEl.textContent = "";
var fd = new FormData(form);
var username = fd.get("username");
var password = fd.get("password");
fetch("/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "same-origin",
body: JSON.stringify({ username: username, password: password }),
})
.then(function (r) {
return r.json().then(function (j) {
return { ok: r.ok, status: r.status, body: j };
});
})
.then(function (x) {
if (x.ok && x.body && x.body.redirect) {
window.location.href = x.body.redirect;
return;
}
errEl.textContent = (x.body && x.body.detail) || "登录失败";
})
.catch(function () {
errEl.textContent = "网络错误";
});
});
})();
</script>
</body>
</html>