362 lines
37 KiB
HTML
362 lines
37 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="theme-color" content="#f3f5f1">
|
||
<title>FluxIP</title>
|
||
<link rel="stylesheet" href="/static/styles.css">
|
||
</head>
|
||
<body>
|
||
<div class="ambient-grid" aria-hidden="true"></div>
|
||
|
||
<main id="boot-screen" class="boot-screen" aria-live="polite">
|
||
<div class="brand-mark brand-mark-large"><span></span><span></span></div>
|
||
<div class="boot-line"><span></span></div>
|
||
</main>
|
||
|
||
<main id="auth-screen" class="auth-screen hidden">
|
||
<section class="auth-panel glass-surface" aria-labelledby="auth-title">
|
||
<div class="auth-brand">
|
||
<div class="brand-mark"><span></span><span></span></div>
|
||
<span>FluxIP</span>
|
||
</div>
|
||
<div class="auth-copy">
|
||
<p id="auth-kicker" class="eyebrow">PRIVATE CONTROL PLANE</p>
|
||
<h1 id="auth-title">创建管理员</h1>
|
||
<p id="auth-subtitle">完成初始化后进入控制台</p>
|
||
</div>
|
||
<form id="auth-form" class="form-stack" novalidate>
|
||
<label class="field">
|
||
<span>用户名</span>
|
||
<span class="input-shell"><i data-lucide="user-round"></i><input id="auth-username" name="username" autocomplete="username" maxlength="40" aria-describedby="auth-username-error" required></span>
|
||
<small id="auth-username-error" class="field-error" data-error-for="username" role="alert"></small>
|
||
</label>
|
||
<label class="field">
|
||
<span>密码</span>
|
||
<span class="input-shell"><i data-lucide="key-round"></i><input id="auth-password" name="password" type="password" autocomplete="new-password" maxlength="128" aria-describedby="auth-password-error" required></span>
|
||
<small id="auth-password-error" class="field-error" data-error-for="password" role="alert"></small>
|
||
</label>
|
||
<label id="bootstrap-token-field" class="field hidden">
|
||
<span>初始化令牌</span>
|
||
<span class="input-shell"><i data-lucide="shield-check"></i><input id="auth-bootstrap-token" name="bootstrap_token" type="password" autocomplete="off" maxlength="512" aria-describedby="auth-bootstrap-token-error"></span>
|
||
<small id="auth-bootstrap-token-error" class="field-error" data-error-for="bootstrap_token" role="alert"></small>
|
||
</label>
|
||
<button id="auth-submit" class="button button-primary button-wide" type="submit"><span>创建并进入</span><i data-lucide="arrow-right"></i></button>
|
||
</form>
|
||
<div class="auth-footer"><span class="status-dot status-dot-ok"></span><span>密钥本地加密存储</span></div>
|
||
</section>
|
||
</main>
|
||
|
||
<div id="app-shell" class="app-shell hidden">
|
||
<aside class="sidebar glass-surface">
|
||
<div class="sidebar-brand">
|
||
<div class="brand-mark"><span></span><span></span></div>
|
||
<div><strong>FluxIP</strong><small>CONTROL</small></div>
|
||
</div>
|
||
<nav class="primary-nav" aria-label="主导航">
|
||
<button class="nav-item active" data-view="overview" type="button"><i data-lucide="layout-dashboard"></i><span>概览</span></button>
|
||
<button class="nav-item" data-view="instances" type="button"><i data-lucide="server"></i><span>实例</span></button>
|
||
<button class="nav-item" data-view="groups" type="button"><i data-lucide="boxes"></i><span>分组</span></button>
|
||
<button class="nav-item" data-view="history" type="button"><i data-lucide="history"></i><span>记录</span></button>
|
||
</nav>
|
||
<div class="sidebar-foot">
|
||
<button id="settings-button" class="sidebar-action" type="button"><i data-lucide="settings-2"></i><span>共享凭据</span></button>
|
||
<button id="account-button" class="account-button" type="button">
|
||
<span class="avatar">A</span>
|
||
<span><strong id="sidebar-username">admin</strong><small>管理员</small></span>
|
||
<i data-lucide="chevron-right"></i>
|
||
</button>
|
||
</div>
|
||
</aside>
|
||
|
||
<header class="mobile-header glass-surface">
|
||
<div class="sidebar-brand"><div class="brand-mark"><span></span><span></span></div><strong>FluxIP</strong></div>
|
||
<div class="mobile-header-actions">
|
||
<button id="mobile-settings" class="icon-button" type="button" aria-label="共享凭据" title="共享凭据"><i data-lucide="settings-2"></i></button>
|
||
<button id="mobile-refresh" class="icon-button" type="button" aria-label="刷新当前页面" title="刷新当前页面"><i data-lucide="refresh-cw"></i></button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="content-frame">
|
||
<section id="view-overview" class="view active-view" data-view-panel="overview">
|
||
<header class="page-header">
|
||
<div><p id="greeting" class="eyebrow">早上好</p><h1>轮换概览</h1></div>
|
||
<div class="header-actions">
|
||
<button id="refresh-overview" class="icon-button" type="button" aria-label="刷新概览" title="刷新概览"><i data-lucide="refresh-cw"></i></button>
|
||
<button class="button button-dark" data-create-instance type="button" aria-label="新增实例" title="新增实例"><i data-lucide="plus"></i><span>新增实例</span></button>
|
||
</div>
|
||
</header>
|
||
|
||
<div id="overview-alert" class="alert-banner hidden" role="status"><i data-lucide="triangle-alert"></i><span></span><button type="button" data-view="instances">查看实例</button></div>
|
||
|
||
<div id="overview-loading" class="overview-loading">
|
||
<div class="skeleton skeleton-status"></div>
|
||
<div class="skeleton-grid"><div class="skeleton skeleton-panel"></div><div class="skeleton skeleton-panel"></div></div>
|
||
</div>
|
||
|
||
<div id="overview-content" class="hidden">
|
||
<section class="status-band fleet-status-band glass-surface" aria-label="实例总体状态">
|
||
<div class="status-primary">
|
||
<div id="fleet-status-icon" class="status-symbol status-symbol-idle"><i data-lucide="radio-tower"></i></div>
|
||
<div><span class="metric-label">已启用实例</span><strong id="fleet-health" class="fleet-display">0 / 0</strong><span id="fleet-status-text" class="inline-status"><span class="status-dot"></span>等待配置</span></div>
|
||
</div>
|
||
<div class="status-metric"><span class="metric-label">运行中任务</span><strong id="fleet-active-runs">0</strong><small>实例轮换</small></div>
|
||
<div class="status-metric"><span class="metric-label">实例组</span><strong id="fleet-groups">0 / 0</strong><small>已启用 / 全部</small></div>
|
||
<div class="status-metric status-metric-last"><span class="metric-label">最近下次轮换</span><strong id="fleet-next-run">已暂停</strong><small id="fleet-next-group">未启用计划</small></div>
|
||
</section>
|
||
|
||
<div class="overview-grid">
|
||
<section class="operations-panel glass-surface">
|
||
<div class="section-heading"><div><span class="eyebrow">ACTIVE ROTATION</span><h2>当前任务</h2></div><span id="active-run-badge" class="badge badge-neutral">空闲</span></div>
|
||
<div id="active-run-empty" class="compact-empty"><i data-lucide="check-circle-2"></i><strong>当前没有运行中的任务</strong><span>队列状态正常</span></div>
|
||
<div id="active-run-panel" class="active-operation hidden">
|
||
<div class="active-operation-main"><span class="service-glyph service-glyph-proxy"><i data-lucide="replace"></i></span><div><small id="active-run-scope">实例轮换</small><strong id="active-run-name">--</strong><span id="active-run-stage">正在预检</span></div><b id="active-run-count">0 / 0</b></div>
|
||
<div class="progress-bar"><span id="active-progress-bar"></span></div>
|
||
<button id="open-active-run" class="text-button" type="button">查看任务详情<i data-lucide="arrow-up-right"></i></button>
|
||
</div>
|
||
</section>
|
||
|
||
<aside class="control-panel next-run-panel glass-surface">
|
||
<div class="section-heading"><div><span class="eyebrow">NEXT GROUP</span><h2>下次轮换</h2></div><i data-lucide="calendar-clock"></i></div>
|
||
<div class="countdown-block"><span id="next-group-name">暂无计划</span><strong id="countdown">--:--:--</strong></div>
|
||
<div class="control-meta"><span><i data-lucide="repeat-2"></i><span>轮换周期</span><strong id="next-group-interval">--</strong></span><span><i data-lucide="server"></i><span>组内实例</span><strong id="next-group-members">--</strong></span></div>
|
||
<button id="overview-open-groups" class="button button-secondary button-wide" type="button"><i data-lucide="boxes"></i><span>管理实例组</span></button>
|
||
</aside>
|
||
</div>
|
||
|
||
<section class="activity-section">
|
||
<div class="section-heading"><div><span class="eyebrow">GROUP STATUS</span><h2>实例组</h2></div><button class="text-button" type="button" data-view="groups">查看全部<i data-lucide="arrow-up-right"></i></button></div>
|
||
<div class="table-wrap glass-surface resource-table-wrap">
|
||
<table class="group-overview-table"><thead><tr><th>实例组</th><th>成员</th><th>轮换周期</th><th>下次执行</th><th>状态</th><th><span class="sr-only">操作</span></th></tr></thead><tbody id="overview-groups"></tbody></table>
|
||
<div id="overview-groups-empty" class="empty-state hidden"><i data-lucide="boxes"></i><strong>还没有实例组</strong><span>创建分组后统一安排轮换</span><button class="button button-secondary" data-create-group type="button"><i data-lucide="plus"></i><span>新增分组</span></button></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="activity-section">
|
||
<div class="section-heading"><div><span class="eyebrow">RECENT ACTIVITY</span><h2>最近轮换</h2></div><button class="text-button" type="button" data-view="history">查看全部<i data-lucide="arrow-up-right"></i></button></div>
|
||
<div class="table-wrap glass-surface resource-table-wrap">
|
||
<table class="recent-table"><thead><tr><th>时间</th><th>目标</th><th>触发</th><th>IP 变化</th><th>状态</th><th><span class="sr-only">操作</span></th></tr></thead><tbody id="recent-runs"></tbody></table>
|
||
<div id="recent-empty" class="empty-state hidden"><i data-lucide="route"></i><strong>还没有轮换记录</strong><span>实例准备完成后即可开始</span></div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="view-instances" class="view" data-view-panel="instances">
|
||
<header class="page-header">
|
||
<div><p class="eyebrow">ROUTES</p><h1>实例</h1></div>
|
||
<button class="button button-primary" data-create-instance type="button" aria-label="新增实例" title="新增实例"><i data-lucide="plus"></i><span>新增实例</span></button>
|
||
</header>
|
||
<div class="resource-toolbar" aria-label="实例筛选">
|
||
<label class="input-shell search-shell"><i data-lucide="search"></i><input id="instance-search" type="search" placeholder="搜索名称、实例或域名" aria-label="搜索实例"></label>
|
||
<div class="custom-select custom-select-compact" data-custom-select>
|
||
<input id="instance-group-filter" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="instance-group-filter-options" aria-label="按实例组筛选"><i data-lucide="boxes"></i><span class="custom-select-value" data-custom-select-label>全部分组</span><i class="custom-select-chevron" data-lucide="chevron-down"></i></button>
|
||
<div id="instance-group-filter-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-label="按实例组筛选" hidden></div>
|
||
</div>
|
||
<div class="custom-select custom-select-compact" data-custom-select>
|
||
<input id="instance-status-filter" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="instance-status-filter-options" aria-label="按状态筛选"><i data-lucide="activity"></i><span class="custom-select-value" data-custom-select-label>全部状态</span><i class="custom-select-chevron" data-lucide="chevron-down"></i></button>
|
||
<div id="instance-status-filter-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-label="按状态筛选" hidden></div>
|
||
</div>
|
||
<button id="refresh-instances" class="icon-button" type="button" aria-label="刷新实例" title="刷新实例"><i data-lucide="refresh-cw"></i></button>
|
||
</div>
|
||
<div id="instances-loading" class="resource-loading hidden"><div class="skeleton skeleton-list"></div></div>
|
||
<div id="instances-table-wrap" class="table-wrap glass-surface resource-table-wrap">
|
||
<table class="instances-table"><thead><tr><th>实例</th><th>实例组</th><th>Cloudflare 路由</th><th>当前 Static IP</th><th>状态</th><th>最近检查</th><th><span class="sr-only">操作</span></th></tr></thead><tbody id="instance-rows"></tbody></table>
|
||
<div id="instances-empty" class="empty-state hidden"><i data-lucide="server"></i><strong>没有匹配的实例</strong><span id="instances-empty-copy">新增第一条 Lightsail 路由</span><button class="button button-secondary" data-create-instance type="button"><i data-lucide="plus"></i><span>新增实例</span></button></div>
|
||
</div>
|
||
<div id="instances-pagination" class="pagination hidden"><button id="instances-prev" class="icon-button" type="button" aria-label="上一页" title="上一页"><i data-lucide="chevron-left"></i></button><span id="instances-page">第 1 页</span><button id="instances-next" class="icon-button" type="button" aria-label="下一页" title="下一页"><i data-lucide="chevron-right"></i></button></div>
|
||
</section>
|
||
|
||
<section id="view-groups" class="view" data-view-panel="groups">
|
||
<header class="page-header">
|
||
<div><p class="eyebrow">AUTOMATION</p><h1>实例组</h1></div>
|
||
<button class="button button-primary" data-create-group type="button" aria-label="新增分组" title="新增分组"><i data-lucide="plus"></i><span>新增分组</span></button>
|
||
</header>
|
||
<div class="resource-toolbar group-toolbar" aria-label="实例组筛选">
|
||
<label class="input-shell search-shell"><i data-lucide="search"></i><input id="group-search" type="search" placeholder="搜索实例组" aria-label="搜索实例组"></label>
|
||
<div class="custom-select custom-select-compact" data-custom-select>
|
||
<input id="group-status-filter" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="group-status-filter-options" aria-label="按计划状态筛选"><i data-lucide="timer-reset"></i><span class="custom-select-value" data-custom-select-label>全部状态</span><i class="custom-select-chevron" data-lucide="chevron-down"></i></button>
|
||
<div id="group-status-filter-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-label="按计划状态筛选" hidden></div>
|
||
</div>
|
||
<button id="refresh-groups" class="icon-button" type="button" aria-label="刷新分组" title="刷新分组"><i data-lucide="refresh-cw"></i></button>
|
||
</div>
|
||
<div id="groups-loading" class="resource-loading hidden"><div class="skeleton skeleton-list"></div></div>
|
||
<div id="groups-table-wrap" class="table-wrap glass-surface resource-table-wrap">
|
||
<table class="groups-table"><thead><tr><th>实例组</th><th>成员</th><th>轮换周期</th><th>下次执行</th><th>上次执行</th><th>状态</th><th><span class="sr-only">操作</span></th></tr></thead><tbody id="group-rows"></tbody></table>
|
||
<div id="groups-empty" class="empty-state hidden"><i data-lucide="boxes"></i><strong>没有匹配的实例组</strong><span id="groups-empty-copy">将多个实例放入同一轮换计划</span><button class="button button-secondary" data-create-group type="button"><i data-lucide="plus"></i><span>新增分组</span></button></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="view-history" class="view" data-view-panel="history">
|
||
<header class="page-header"><div><p class="eyebrow">AUDIT TRAIL</p><h1>轮换记录</h1></div><button id="refresh-history" class="icon-button" type="button" aria-label="刷新记录" title="刷新记录"><i data-lucide="refresh-cw"></i></button></header>
|
||
<div class="resource-toolbar history-toolbar" aria-label="记录筛选">
|
||
<div class="custom-select custom-select-compact" data-custom-select>
|
||
<input id="history-instance-filter" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="history-instance-filter-options" aria-label="按实例筛选"><i data-lucide="server"></i><span class="custom-select-value" data-custom-select-label>全部实例</span><i class="custom-select-chevron" data-lucide="chevron-down"></i></button>
|
||
<div id="history-instance-filter-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-label="按实例筛选" hidden></div>
|
||
</div>
|
||
<div class="custom-select custom-select-compact" data-custom-select>
|
||
<input id="history-group-filter" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="history-group-filter-options" aria-label="按实例组筛选"><i data-lucide="boxes"></i><span class="custom-select-value" data-custom-select-label>全部分组</span><i class="custom-select-chevron" data-lucide="chevron-down"></i></button>
|
||
<div id="history-group-filter-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-label="按实例组筛选" hidden></div>
|
||
</div>
|
||
<div class="custom-select custom-select-compact" data-custom-select>
|
||
<input id="history-status-filter" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="history-status-filter-options" aria-label="按结果筛选"><i data-lucide="activity"></i><span class="custom-select-value" data-custom-select-label>全部结果</span><i class="custom-select-chevron" data-lucide="chevron-down"></i></button>
|
||
<div id="history-status-filter-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-label="按结果筛选" hidden></div>
|
||
</div>
|
||
</div>
|
||
<div id="history-loading" class="resource-loading hidden"><div class="skeleton skeleton-list"></div></div>
|
||
<section class="history-summary" aria-label="记录摘要"><div><span>全部任务</span><strong id="history-total">0</strong></div><div><span>成功率</span><strong id="history-rate">--</strong></div><div><span>最近成功</span><strong id="history-latest">--</strong></div></section>
|
||
<div class="table-wrap history-table glass-surface resource-table-wrap"><table><thead><tr><th>开始时间</th><th>目标</th><th>触发</th><th>完成进度 / IP 变化</th><th>结果</th><th><span class="sr-only">详情</span></th></tr></thead><tbody id="history-runs"></tbody></table><div id="history-empty" class="empty-state hidden"><i data-lucide="history"></i><strong>暂无记录</strong><span>调整筛选或开始一次轮换</span></div></div>
|
||
<div class="pagination"><button id="history-prev" class="icon-button" type="button" aria-label="上一页" title="上一页"><i data-lucide="chevron-left"></i></button><span id="history-page">第 1 页</span><button id="history-next" class="icon-button" type="button" aria-label="下一页" title="下一页"><i data-lucide="chevron-right"></i></button></div>
|
||
</section>
|
||
</div>
|
||
|
||
<nav class="mobile-nav glass-surface" aria-label="移动端导航">
|
||
<button class="nav-item active" data-view="overview" type="button"><i data-lucide="layout-dashboard"></i><span>概览</span></button>
|
||
<button class="nav-item" data-view="instances" type="button"><i data-lucide="server"></i><span>实例</span></button>
|
||
<button class="nav-item" data-view="groups" type="button"><i data-lucide="boxes"></i><span>分组</span></button>
|
||
<button class="nav-item" data-view="history" type="button"><i data-lucide="history"></i><span>记录</span></button>
|
||
</nav>
|
||
</div>
|
||
|
||
<dialog id="instance-dialog" class="modal-dialog editor-dialog" aria-labelledby="instance-dialog-title">
|
||
<form id="instance-form" novalidate>
|
||
<div class="dialog-header sticky-dialog-head"><div><span class="eyebrow">INSTANCE</span><h2 id="instance-dialog-title">新增实例</h2></div><button class="icon-button" data-close-dialog type="button" aria-label="关闭" title="关闭"><i data-lucide="x"></i></button></div>
|
||
<section class="editor-section">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-proxy"><i data-lucide="route"></i></span><div><span class="eyebrow">IDENTITY</span><h3>路由身份</h3></div></div>
|
||
<div class="form-grid form-grid-2">
|
||
<label class="field"><span>显示名称</span><span class="input-shell"><i data-lucide="tag"></i><input name="display_name" maxlength="80" placeholder="新加坡代理 01" required></span><small class="field-error" data-error-for="display_name"></small></label>
|
||
<div class="field">
|
||
<span id="instance-group-label">所属实例组</span>
|
||
<div id="instance-group-select" class="custom-select custom-select-rich" data-custom-select>
|
||
<input name="group_id" type="hidden" value="">
|
||
<button class="custom-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false" aria-controls="instance-group-options" aria-labelledby="instance-group-label instance-group-select-value">
|
||
<i data-lucide="boxes"></i>
|
||
<span id="instance-group-select-value" class="custom-select-value" data-custom-select-label>未分组</span>
|
||
<i class="custom-select-chevron" data-lucide="chevron-down"></i>
|
||
</button>
|
||
<div id="instance-group-options" class="custom-select-menu" data-custom-select-menu role="listbox" aria-labelledby="instance-group-label" hidden></div>
|
||
</div>
|
||
<small class="field-error" data-error-for="group_id"></small>
|
||
</div>
|
||
</div>
|
||
<label class="toggle-row"><span><strong>启用此实例</strong><small>停用后不参与组计划</small></span><input name="enabled" type="checkbox" checked><span class="toggle" aria-hidden="true"></span></label>
|
||
</section>
|
||
<section class="editor-section">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-aws"><i data-lucide="server"></i></span><div><span class="eyebrow">AMAZON LIGHTSAIL</span><h3>目标实例</h3></div></div>
|
||
<div class="form-grid form-grid-2">
|
||
<label class="field"><span>AWS Region</span><span class="input-shell"><i data-lucide="map-pin"></i><input name="aws_region" maxlength="32" placeholder="ap-southeast-1" required></span><small class="field-error" data-error-for="aws_region"></small></label>
|
||
<label class="field"><span>Lightsail 实例名</span><span class="input-shell"><i data-lucide="box"></i><input name="lightsail_instance_name" maxlength="255" placeholder="socks-gateway" required></span><small class="field-error" data-error-for="lightsail_instance_name"></small></label>
|
||
</div>
|
||
</section>
|
||
<section class="editor-section">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-cf"><i data-lucide="cloud"></i></span><div><span class="eyebrow">CLOUDFLARE DNS</span><h3>域名路由</h3></div></div>
|
||
<div class="form-grid form-grid-2">
|
||
<label class="field"><span>Zone 根域名</span><span class="input-shell"><i data-lucide="globe-2"></i><input name="cloudflare_zone_name" maxlength="253" placeholder="example.com" required></span><small class="field-error" data-error-for="cloudflare_zone_name"></small></label>
|
||
<label class="field"><span>Zone ID <small>可选</small></span><span class="input-shell"><i data-lucide="scan-line"></i><input name="cloudflare_zone_id" maxlength="64" placeholder="留空自动查找"></span><small class="field-error" data-error-for="cloudflare_zone_id"></small></label>
|
||
<label class="field field-span-2"><span>A 记录完整域名</span><span class="input-shell"><i data-lucide="at-sign"></i><input name="cloudflare_record_name" maxlength="253" placeholder="proxy.example.com" required></span><small class="field-error" data-error-for="cloudflare_record_name"></small></label>
|
||
</div>
|
||
<div class="compatibility-note"><span class="note-icon"><i data-lucide="cloud-off"></i></span><div><strong>DNS-only · TTL 60s</strong><span>SOCKS5 路由保持灰云解析</span></div></div>
|
||
</section>
|
||
<section class="editor-section">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-health"><i data-lucide="activity"></i></span><div><span class="eyebrow">AVAILABILITY</span><h3>切换检查</h3></div></div>
|
||
<div class="form-grid form-grid-3">
|
||
<label class="field"><span>SOCKS5 端口</span><span class="input-shell"><i data-lucide="network"></i><input name="socks_port" type="number" min="1" max="65535" value="1080" required></span></label>
|
||
<label class="field"><span>检查超时</span><span class="input-shell"><i data-lucide="clock-3"></i><input name="health_timeout_seconds" type="number" min="10" max="600" value="120" required><em>秒</em></span></label>
|
||
<label class="field"><span>释放等待</span><span class="input-shell"><i data-lucide="hourglass"></i><input name="release_grace_seconds" type="number" min="60" max="600" value="75" required><em>秒</em></span></label>
|
||
</div>
|
||
<label class="toggle-row"><span><strong>DNS 切换前检查 SOCKS5</strong><small>新 Static IP 可连接后再更新域名</small></span><input name="proxy_health_check" type="checkbox" checked><span class="toggle" aria-hidden="true"></span></label>
|
||
</section>
|
||
<div class="form-footer sticky-dialog-foot"><button id="delete-instance" class="button button-danger-soft hidden" type="button"><i data-lucide="trash-2"></i><span>删除</span></button><span id="instance-save-state"></span><button id="test-instance-dialog" class="button button-secondary hidden" type="button"><i data-lucide="plug-zap"></i><span>测试</span></button><button id="save-instance" class="button button-primary" type="submit"><i data-lucide="save"></i><span>保存实例</span></button></div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="group-dialog" class="modal-dialog editor-dialog group-editor-dialog" aria-labelledby="group-dialog-title">
|
||
<form id="group-form" novalidate>
|
||
<div class="dialog-header sticky-dialog-head"><div><span class="eyebrow">INSTANCE GROUP</span><h2 id="group-dialog-title">新增分组</h2></div><button class="icon-button" data-close-dialog type="button" aria-label="关闭" title="关闭"><i data-lucide="x"></i></button></div>
|
||
<section class="editor-section group-identity-section">
|
||
<div class="form-grid form-grid-2 group-title-grid">
|
||
<label class="field"><span>分组名称</span><span class="input-shell"><i data-lucide="boxes"></i><input name="name" maxlength="80" placeholder="亚太代理池" required></span><small class="field-error" data-error-for="name"></small></label>
|
||
<label class="standalone-toggle group-enabled-toggle"><input name="enabled" type="checkbox"><span class="toggle" aria-hidden="true"></span><span data-group-enabled-label>计划已暂停</span></label>
|
||
</div>
|
||
</section>
|
||
<section class="editor-section schedule-editor">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-schedule"><i data-lucide="timer-reset"></i></span><div><span class="eyebrow">SCHEDULE</span><h3>轮换周期</h3></div></div>
|
||
<div class="schedule-config group-schedule-config">
|
||
<div><span class="field-label">常用周期</span><div id="group-interval-presets" class="preset-group"><button type="button" data-group-minutes="30">30 分钟</button><button type="button" data-group-minutes="60" class="active">1 小时</button><button type="button" data-group-minutes="360">6 小时</button><button type="button" data-group-minutes="1440">24 小时</button></div></div>
|
||
<label class="field interval-custom"><span>自定义分钟</span><span class="input-shell"><i data-lucide="sliders-horizontal"></i><input name="interval_minutes" type="number" min="5" max="10080" value="60" required><em>分钟</em></span><small class="field-error" data-error-for="interval_minutes"></small></label>
|
||
</div>
|
||
</section>
|
||
<section class="editor-section member-editor-section">
|
||
<div class="editor-section-title member-heading"><span class="service-glyph service-glyph-members"><i data-lucide="server"></i></span><div><span class="eyebrow">MEMBERS</span><h3>组内实例</h3></div><span id="selected-member-count" class="badge badge-neutral">0 个</span></div>
|
||
<label class="input-shell member-search"><i data-lucide="search"></i><input id="group-member-search" type="search" placeholder="搜索实例或域名" aria-label="搜索可选实例"></label>
|
||
<div id="group-member-list" class="member-list" role="group" aria-label="选择实例"></div>
|
||
<div id="group-members-empty" class="compact-empty hidden"><i data-lucide="server-off"></i><strong>没有可选实例</strong><span>先创建一个实例</span></div>
|
||
</section>
|
||
<div class="form-footer sticky-dialog-foot"><button id="delete-group" class="button button-danger-soft hidden" type="button"><i data-lucide="trash-2"></i><span>删除</span></button><span id="group-save-state"></span><button id="save-group" class="button button-primary" type="submit"><i data-lucide="save"></i><span>保存分组</span></button></div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="settings-dialog" class="modal-dialog editor-dialog settings-dialog" aria-labelledby="settings-dialog-title">
|
||
<form id="settings-form" novalidate>
|
||
<div class="dialog-header sticky-dialog-head"><div><span class="eyebrow">SHARED CREDENTIALS</span><h2 id="settings-dialog-title">共享凭据</h2></div><button class="icon-button" data-close-dialog type="button" aria-label="关闭" title="关闭"><i data-lucide="x"></i></button></div>
|
||
<section class="editor-section">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-aws"><i data-lucide="key-round"></i></span><div><span class="eyebrow">AMAZON WEB SERVICES</span><h3>AWS 凭据</h3></div><span id="aws-config-badge" class="badge badge-neutral">未配置</span></div>
|
||
<div class="segmented-control" aria-label="AWS 凭据方式"><button type="button" data-aws-mode="access">访问密钥</button><button type="button" data-aws-mode="default">默认凭据链</button></div>
|
||
<input type="hidden" name="use_default_aws_credentials" value="false">
|
||
<div id="aws-secret-fields" class="form-grid form-grid-2 secret-grid">
|
||
<label class="field"><span>Access Key ID</span><span class="input-shell"><i data-lucide="fingerprint"></i><input name="aws_access_key_id" autocomplete="off" maxlength="128"></span><small class="field-error" data-error-for="aws_access_key_id"></small></label>
|
||
<label class="field"><span>Secret Access Key</span><span class="input-shell"><i data-lucide="key-round"></i><input name="aws_secret_access_key" type="password" autocomplete="new-password" maxlength="256"></span><small class="field-error" data-error-for="aws_secret_access_key"></small></label>
|
||
<label class="field field-span-2"><span>Session Token <small>可选</small></span><span class="input-shell"><i data-lucide="ticket-check"></i><input name="aws_session_token" type="password" autocomplete="new-password" maxlength="4096"></span></label>
|
||
</div>
|
||
</section>
|
||
<section class="editor-section">
|
||
<div class="editor-section-title"><span class="service-glyph service-glyph-cf"><i data-lucide="shield-keyhole"></i></span><div><span class="eyebrow">CLOUDFLARE</span><h3>API Token</h3></div><span id="cf-config-badge" class="badge badge-neutral">未配置</span></div>
|
||
<label class="field"><span>Cloudflare API Token</span><span class="input-shell"><i data-lucide="shield-check"></i><input name="cloudflare_api_token" type="password" autocomplete="new-password" maxlength="2048"></span><small class="field-error" data-error-for="cloudflare_api_token"></small></label>
|
||
</section>
|
||
<div class="form-footer sticky-dialog-foot"><span id="settings-save-state"></span><button id="save-settings" class="button button-primary" type="submit"><i data-lucide="save"></i><span>保存凭据</span></button></div>
|
||
</form>
|
||
</dialog>
|
||
|
||
<dialog id="rotation-confirm-dialog" class="modal-dialog" aria-labelledby="rotation-confirm-title">
|
||
<div class="modal-icon modal-icon-warn"><i data-lucide="replace"></i></div><h2 id="rotation-confirm-title">立即轮换 Static IP?</h2><p id="rotation-confirm-copy">实例不会关机,切换地址时现有 SOCKS5 连接仍会中断。新 IP 与 DNS 验证成功后,系统将释放旧 Static IP。</p>
|
||
<div id="rotation-confirm-meta" class="confirm-meta"></div>
|
||
<div class="modal-actions"><button class="button button-secondary" data-close-dialog type="button">取消</button><button id="confirm-rotation" class="button button-dark" type="button"><i data-lucide="rotate-cw"></i><span>确认轮换</span></button></div>
|
||
</dialog>
|
||
|
||
<dialog id="delete-confirm-dialog" class="modal-dialog" aria-labelledby="delete-confirm-title">
|
||
<div class="modal-icon modal-icon-danger"><i data-lucide="trash-2"></i></div><h2 id="delete-confirm-title">删除配置?</h2><p id="delete-confirm-copy">该配置将从控制台移除,当前附加的 Static IP 不会被主动释放。</p>
|
||
<div class="modal-actions"><button class="button button-secondary" data-close-dialog type="button">取消</button><button id="confirm-delete" class="button button-danger" type="button"><i data-lucide="trash-2"></i><span>确认删除</span></button></div>
|
||
</dialog>
|
||
|
||
<dialog id="run-dialog" class="modal-dialog run-dialog" aria-labelledby="run-dialog-title">
|
||
<div class="dialog-header"><div><span class="eyebrow">RUN DETAILS</span><h2 id="run-dialog-title">任务详情</h2></div><button class="icon-button" data-close-dialog type="button" aria-label="关闭" title="关闭"><i data-lucide="x"></i></button></div>
|
||
<div id="run-dialog-summary" class="run-dialog-summary"></div>
|
||
<div id="run-items-wrap" class="run-items-wrap hidden"><div class="run-subheading"><span>实例进度</span><strong id="run-items-count">0 / 0</strong></div><div id="run-items" class="run-items"></div></div>
|
||
<div class="run-subheading"><span>任务事件</span></div><ol id="run-events" class="event-timeline"></ol>
|
||
<div id="resume-run-wrap" class="modal-actions run-recovery-actions hidden"><button id="cancel-run" class="button button-danger" type="button"><i data-lucide="octagon-x"></i><span>放弃任务</span></button><button id="resume-run" class="button button-primary" type="button"><i data-lucide="play"></i><span>继续处理</span></button></div>
|
||
</dialog>
|
||
|
||
<dialog id="cancel-run-dialog" class="modal-dialog" aria-labelledby="cancel-run-title">
|
||
<div class="modal-icon modal-icon-warn"><i data-lucide="triangle-alert"></i></div><h2 id="cancel-run-title">放弃当前任务?</h2><p>系统将停止自动恢复。请在完成后核对实例、Cloudflare DNS 和旧 Static IP 的释放状态。</p>
|
||
<div class="modal-actions"><button class="button button-secondary" data-close-dialog type="button">返回</button><button id="confirm-cancel-run" class="button button-danger" type="button"><i data-lucide="octagon-x"></i><span>确认放弃</span></button></div>
|
||
</dialog>
|
||
|
||
<dialog id="account-dialog" class="modal-dialog account-dialog" aria-labelledby="account-dialog-title">
|
||
<div class="dialog-header"><div><span class="eyebrow">ACCOUNT</span><h2 id="account-dialog-title">管理员账户</h2></div><button class="icon-button" data-close-dialog type="button" aria-label="关闭" title="关闭"><i data-lucide="x"></i></button></div>
|
||
<form id="password-form" class="form-stack" novalidate><label class="field"><span>当前密码</span><span class="input-shell"><i data-lucide="key-round"></i><input name="current_password" type="password" autocomplete="current-password" required></span></label><label class="field"><span>新密码</span><span class="input-shell"><i data-lucide="shield-check"></i><input name="new_password" type="password" autocomplete="new-password" minlength="10" required></span></label><button class="button button-primary button-wide" type="submit"><i data-lucide="save"></i><span>更新密码</span></button></form>
|
||
<div class="account-divider"></div><button id="logout-button" class="button button-secondary button-wide" type="button"><i data-lucide="log-out"></i><span>退出登录</span></button>
|
||
</dialog>
|
||
|
||
<div id="toast-region" class="toast-region" aria-live="polite" aria-atomic="true"></div>
|
||
<script src="/static/vendor/lucide.min.js"></script>
|
||
<script src="/static/app.js"></script>
|
||
</body>
|
||
</html>
|