ea24149a55
Co-authored-by: Cursor <cursoragent@cursor.com>
192 lines
10 KiB
HTML
192 lines
10 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}系统设置 · 期权中控{% endblock %}
|
|
{% block body %}
|
|
{% set _tab = (request.args.get('tab') or 'account').strip() %}
|
|
{% if _tab not in ('account', 'wechat', 'backup', 'update') %}{% set _tab = 'account' %}{% endif %}
|
|
<section class="page-head settings-head">
|
|
<div>
|
|
<p class="settings-eyebrow">Hub Settings</p>
|
|
<h1>系统设置</h1>
|
|
<p class="muted settings-lead">账号、告警、备份与系统更新在此维护;保存后立即生效。</p>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="settings-shell panel">
|
|
<input type="radio" name="hub-settings-tab" id="hub-set-account" class="settings-tab-radio"{% if _tab == 'account' %} checked{% endif %}>
|
|
<input type="radio" name="hub-settings-tab" id="hub-set-wechat" class="settings-tab-radio"{% if _tab == 'wechat' %} checked{% endif %}>
|
|
<input type="radio" name="hub-settings-tab" id="hub-set-backup" class="settings-tab-radio"{% if _tab == 'backup' %} checked{% endif %}>
|
|
<input type="radio" name="hub-settings-tab" id="hub-set-update" class="settings-tab-radio"{% if _tab == 'update' %} checked{% endif %}>
|
|
|
|
<div class="settings-tabs" role="tablist" aria-label="系统设置分类">
|
|
<label for="hub-set-account" class="settings-tab-btn" role="tab">登录账号</label>
|
|
<label for="hub-set-wechat" class="settings-tab-btn" role="tab">企业微信</label>
|
|
<label for="hub-set-backup" class="settings-tab-btn" role="tab">备份恢复</label>
|
|
<label for="hub-set-update" class="settings-tab-btn" role="tab">系统更新</label>
|
|
</div>
|
|
|
|
<div class="settings-panels">
|
|
<section class="settings-panel settings-panel--account" role="tabpanel">
|
|
<div class="settings-card-head">
|
|
<span class="settings-badge">Account</span>
|
|
<h2>登录账号</h2>
|
|
<p class="muted">修改后立即写入 <code>.env</code>,无需重启。</p>
|
|
</div>
|
|
<form method="post" class="stack settings-form" autocomplete="off" data-lpignore="true" data-1p-ignore="true">
|
|
<input type="hidden" name="form_action" value="account">
|
|
<input type="hidden" name="return_tab" value="account">
|
|
<div class="settings-field">
|
|
<span class="settings-label">当前用户名</span>
|
|
<div class="settings-readonly">{{ current_username }}</div>
|
|
</div>
|
|
<label class="settings-field">当前密码
|
|
<input type="password" name="current_password" required autocomplete="new-password" placeholder="验证身份后才能保存">
|
|
</label>
|
|
<div class="settings-divider"></div>
|
|
<label class="settings-field">新用户名
|
|
<input type="text" name="new_username" value="{{ current_username }}" required autocomplete="off" minlength="2" maxlength="64">
|
|
</label>
|
|
<div class="settings-row-2">
|
|
<label class="settings-field">新密码
|
|
<input type="password" name="new_password" autocomplete="new-password" minlength="6" placeholder="至少 6 位,不改可留空">
|
|
</label>
|
|
<label class="settings-field">确认新密码
|
|
<input type="password" name="confirm_password" autocomplete="new-password" minlength="6" placeholder="再次输入">
|
|
</label>
|
|
</div>
|
|
<button type="submit" class="settings-primary">保存账号</button>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="settings-panel settings-panel--wechat" role="tabpanel">
|
|
<div class="settings-card-head">
|
|
<span class="settings-badge settings-badge--alert">Notify</span>
|
|
<h2>企业微信告警</h2>
|
|
<p class="muted">中控专用:客户端离线 / 故障 / 恢复时推送,与交易机通知分开。</p>
|
|
</div>
|
|
<form method="post" class="stack settings-form" autocomplete="off">
|
|
<input type="hidden" name="return_tab" value="wechat">
|
|
<label class="settings-switch">
|
|
<input type="checkbox" name="wechat_enabled" value="1"{% if wechat.enabled %} checked{% endif %}>
|
|
<span class="settings-switch-ui" aria-hidden="true"></span>
|
|
<span class="settings-switch-text">
|
|
<strong>启用企业微信推送</strong>
|
|
<small>关闭后后台仍巡检,但不发消息</small>
|
|
</span>
|
|
</label>
|
|
<div class="settings-row-2">
|
|
<label class="settings-field">告警冷却(秒)
|
|
<input type="number" name="alert_cooldown_sec" value="{{ wechat.cooldown_sec }}" min="60" max="86400" step="1">
|
|
</label>
|
|
<label class="settings-field">连续失败阈值
|
|
<input type="number" name="health_fail_threshold" value="{{ wechat.fail_threshold }}" min="1" max="20" step="1">
|
|
</label>
|
|
</div>
|
|
<p class="field-hint settings-hint">连续拉取失败达到阈值后才告警,默认 2 次;同一机器在冷却期内不重复推送。</p>
|
|
<label class="settings-field">Webhook 地址
|
|
<input type="url" name="wechat_webhook" value="{{ wechat.webhook }}" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=..." autocomplete="off">
|
|
</label>
|
|
<div class="settings-actions">
|
|
<button type="submit" name="form_action" value="wechat" class="settings-primary">保存告警配置</button>
|
|
<button type="submit" name="form_action" value="wechat_test" class="btn-secondary">发送测试消息</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="settings-panel settings-panel--backup" role="tabpanel">
|
|
<div class="settings-card-head">
|
|
<span class="settings-badge">Backup</span>
|
|
<h2>备份恢复</h2>
|
|
<p class="muted">每天北京时间 03:00 自动备份,保留最近 10 天。中控可下载本机与各客户端备份;客户端仅能下载自己的。</p>
|
|
</div>
|
|
|
|
<div class="settings-backup-body">
|
|
<div class="backup-block">
|
|
<div class="backup-block-head">
|
|
<h3>中控备份</h3>
|
|
<p class="muted field-hint">目录 <code id="hub-backup-dir">/root/crypto_okx_hub_backups</code> · 含 <code>.env</code> 与 <code>hub.db</code></p>
|
|
<div class="settings-actions">
|
|
<button type="button" class="settings-primary" id="hub-backup-create">立即备份</button>
|
|
<button type="button" class="btn-secondary" id="hub-backup-refresh">刷新</button>
|
|
<span class="muted" id="hub-backup-status" style="font-size:.8rem"></span>
|
|
</div>
|
|
</div>
|
|
<div class="table-wrap">
|
|
<table class="backup-table">
|
|
<thead><tr><th>文件</th><th>时间</th><th>大小</th><th>操作</th></tr></thead>
|
|
<tbody id="hub-backup-body"><tr><td colspan="4" class="muted">加载中…</td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="backup-block">
|
|
<div class="backup-block-head">
|
|
<h3>客户端备份</h3>
|
|
<p class="muted field-hint">经 Bridge 拉取各机备份列表,可下载到本地</p>
|
|
<div class="settings-actions">
|
|
<label class="settings-field settings-field--inline">
|
|
客户端
|
|
<select id="client-backup-instance"></select>
|
|
</label>
|
|
<button type="button" class="btn-secondary" id="client-backup-refresh">刷新</button>
|
|
<span class="muted" id="client-backup-status" style="font-size:.8rem"></span>
|
|
</div>
|
|
</div>
|
|
<div class="table-wrap">
|
|
<table class="backup-table">
|
|
<thead><tr><th>文件</th><th>时间</th><th>大小</th><th>操作</th></tr></thead>
|
|
<tbody id="client-backup-body"><tr><td colspan="4" class="muted">请选择客户端</td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="settings-panel settings-panel--update" role="tabpanel">
|
|
<div class="settings-card-head">
|
|
<span class="settings-badge">Update</span>
|
|
<h2>系统更新</h2>
|
|
<p class="muted">快速更新 = git pull + pm2 restart。中控本机更新;客户端经 Bridge 远程下发。有持仓时慎用。中控更新日志:<code>logs/hub_update.log</code></p>
|
|
</div>
|
|
|
|
<div class="settings-backup-body">
|
|
<div class="backup-block">
|
|
<div class="backup-block-head">
|
|
<h3>中控更新</h3>
|
|
<p class="muted field-hint">当前版本 <code id="hub-update-version" class="update-version">—</code></p>
|
|
<div class="settings-actions">
|
|
<button type="button" class="settings-primary" id="hub-update-btn">更新中控</button>
|
|
<button type="button" class="btn-secondary" id="hub-update-refresh">刷新版本</button>
|
|
<span class="update-status muted" id="hub-update-status"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="backup-block">
|
|
<div class="backup-block-head">
|
|
<h3>客户端远程更新</h3>
|
|
<p class="muted field-hint">经 Bridge 探测版本并下发更新;客户端需已具备 <code>/api/hub/update</code></p>
|
|
<div class="settings-actions">
|
|
<button type="button" class="btn-secondary" id="client-update-refresh">刷新列表</button>
|
|
</div>
|
|
</div>
|
|
<div class="table-wrap">
|
|
<table class="backup-table update-table">
|
|
<thead><tr><th>实例</th><th>版本</th><th>状态</th><th>操作</th></tr></thead>
|
|
<tbody id="client-update-body"><tr><td colspan="4" class="muted">加载中…</td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='settings_backup.js') }}?v=2"></script>
|
|
<script src="{{ url_for('static', filename='settings_update.js') }}?v=3"></script>
|
|
<script>
|
|
HubSettingsBackup.boot();
|
|
HubSettingsUpdate.boot();
|
|
</script>
|
|
{% endblock %}
|