Files
orbit/internal/transport/httpserver/console/index.html

447 lines
49 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark">
<title>Orbit Console · 星轨控制台</title>
<link rel="stylesheet" href="/console/styles.css">
</head>
<body>
<div class="ambient ambient-one"></div>
<div class="ambient ambient-two"></div>
<div class="app-shell">
<aside class="sidebar">
<div class="brand">
<div class="brand-mark"><span></span><span></span><span></span></div>
<div><strong>Orbit</strong><small>星轨控制台</small></div>
</div>
<div class="workspace-label">CONTROL PLANE</div>
<nav class="nav-list" aria-label="控制台导航">
<button class="nav-item active" data-view="overview"><span class="nav-icon">⌂</span><span>总览</span><em>01</em></button>
<button class="nav-item" data-view="tasks"><span class="nav-icon">◇</span><span>任务执行</span><em>02</em></button>
<button class="nav-item" data-view="schedules"><span class="nav-icon">◷</span><span>定时计划</span><em>03</em></button>
<button class="nav-item" data-view="workflows"><span class="nav-icon">⌘</span><span>流程实例</span><em>04</em></button>
<button class="nav-item" data-view="subscriptions"><span class="nav-icon">⌁</span><span>结果订阅</span><em>05</em></button>
<button class="nav-item" data-view="retention"><span class="nav-icon">⌛</span><span>保留策略</span><em>06</em></button>
<button class="nav-item" data-view="archives"><span class="nav-icon">▤</span><span>归档作业</span><em>07</em></button>
<button class="nav-item" data-view="applications"><span class="nav-icon">⊞</span><span>应用接入</span><em>08</em></button>
</nav>
<div class="sidebar-bottom">
<div class="rail-card">
<div class="rail-card-top"><span class="status-dot"></span><span id="side-status">等待连接</span></div>
<p id="side-endpoint">API 未连接</p>
<div class="rail-progress"><span id="side-progress"></span></div>
</div>
<div class="sidebar-foot"><span class="pulse-dot"></span> Pulse · Weave <span class="foot-version">v1</span></div>
</div>
</aside>
<main class="main-content">
<header class="topbar">
<div class="crumbs"><span>Orbit</span><b>/</b><strong id="page-title">总览</strong></div>
<div class="topbar-actions">
<span class="live-chip"><i></i><span id="live-label">本地环境</span></span>
<span class="last-updated" id="last-updated">尚未刷新</span>
<button class="icon-button" id="logout-button" title="退出登录" aria-label="退出登录">↪</button>
<button class="icon-button" id="refresh-button" title="刷新数据" aria-label="刷新数据">↻</button>
</div>
</header>
<section class="application-scope" id="application-scope" aria-label="应用筛选">
<div class="scope-heading"><span class="scope-symbol">⊞</span><div><b>应用范围</b><small id="scope-summary">正在读取…</small></div></div>
<label class="scope-field"><span>应用 / 环境</span><select id="scope-application" disabled aria-label="选择应用与环境"><option>正在读取…</option></select></label>
<label class="scope-field scope-queue"><span>队列</span><select id="scope-queue" disabled aria-label="选择队列"><option>正在读取…</option></select></label>
<div class="scope-note"><small id="scope-hint">任务、计划和订阅按所选队列显示</small><button id="scope-reset" type="button" class="text-button">重置范围 ↗</button></div>
<p id="scope-error" class="scope-error" role="status"></p>
</section>
<div class="page-view active" id="view-overview" data-page="overview">
<section class="hero" id="overview">
<div class="hero-copy">
<div class="eyebrow"><span class="eyebrow-line"></span> ORBIT CONTROL PLANE</div>
<h1>让每一次执行<br><span>都清晰可见。</span></h1>
<p>任务、定时、流程和交付状态,在一块屏幕上保持有序运转。</p>
<div class="hero-actions">
<button class="primary-button" data-view="tasks">查看任务 <span>↗</span></button>
<button class="quiet-button" id="logout-hero">退出登录</button>
</div>
</div>
<div class="hero-visual" aria-hidden="true">
<div class="orbit-ring ring-one"></div>
<div class="orbit-ring ring-two"></div>
<div class="orbit-ring ring-three"></div>
<div class="orbit-core"><span>O</span></div>
<div class="orbit-node node-a"></div><div class="orbit-node node-b"></div><div class="orbit-node node-c"></div>
<div class="hero-visual-label"><b>LIVE</b><span>任务流持续观测</span></div>
</div>
</section>
<section class="metric-grid" aria-label="运行概览">
<article class="metric-card metric-highlight"><div class="metric-top"><span>服务状态</span><span class="metric-icon green">✦</span></div><strong id="metric-health">—</strong><small id="metric-health-sub">等待就绪检查</small><div class="sparkline green-line"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></article>
<article class="metric-card"><div class="metric-top"><span>任务总览</span><span class="metric-icon purple">◇</span></div><strong id="metric-tasks">—</strong><small id="metric-tasks-sub">当前会话加载</small><div class="mini-bar"><i id="task-bar-succeeded"></i><i id="task-bar-running"></i><i id="task-bar-waiting"></i><i id="task-bar-other"></i></div></article>
<article class="metric-card"><div class="metric-top"><span>流程实例</span><span class="metric-icon blue">⌘</span></div><strong id="metric-workflows">—</strong><small id="metric-workflows-sub">等待工作流权限</small><div class="sparkline blue-line"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></article>
<article class="metric-card"><div class="metric-top"><span>结果订阅</span><span class="metric-icon orange">⌁</span></div><strong id="metric-subscriptions">—</strong><small id="metric-subscriptions-sub">等待事件权限</small><div class="subscription-meter"><span id="subscription-meter-fill"></span></div></article>
</section>
<section class="content-grid overview-grid" aria-label="运行统计与连接状态">
<article class="panel stats-panel" id="runtime-stats">
<div class="panel-heading"><div><span class="panel-kicker">RUNTIME / SNAPSHOT</span><h2>运行统计</h2></div><span class="table-count" id="stats-snapshot">等待数据</span></div>
<div class="stat-grid">
<div class="stat-tile"><span>当前窗口成功率</span><strong id="stat-success-rate">—</strong><small id="stat-success-rate-sub">等待任务数据</small></div>
<div class="stat-tile"><span>活跃计划</span><strong id="stat-active-schedules">—</strong><small id="stat-active-schedules-sub">等待计划数据</small></div>
<div class="stat-tile"><span>待核查流程</span><strong id="stat-review-workflows">—</strong><small id="stat-review-workflows-sub">等待流程数据</small></div>
<div class="stat-tile"><span>待交付结果</span><strong id="stat-pending-deliveries">—</strong><small id="stat-pending-deliveries-sub">等待订阅数据</small></div>
</div>
<div class="distribution-block">
<div class="distribution-heading"><span>任务状态分布</span><small id="stat-task-total">—</small></div>
<div class="distribution-list">
<div class="distribution-row"><span>成功</span><div class="status-track"><i id="stat-bar-succeeded"></i></div><b id="stat-count-succeeded">0</b></div>
<div class="distribution-row"><span>执行中</span><div class="status-track"><i id="stat-bar-running"></i></div><b id="stat-count-running">0</b></div>
<div class="distribution-row"><span>等待</span><div class="status-track"><i id="stat-bar-waiting"></i></div><b id="stat-count-waiting">0</b></div>
<div class="distribution-row"><span>异常</span><div class="status-track"><i id="stat-bar-other"></i></div><b id="stat-count-other">0</b></div>
</div>
</div>
</article>
<article class="panel connection-summary-panel">
<div class="panel-heading"><div><span class="panel-kicker">CONTROL PLANE</span><h2>登录状态</h2></div><span class="connection-state" id="connection-state">未连接</span></div>
<div class="connection-summary-copy"><span class="connection-summary-icon">↗</span><div><b id="summary-api">当前页面</b><small id="summary-api-hint">API 地址自动跟随当前页面</small></div></div>
<div class="connection-summary-grid"><div><span>队列范围</span><b id="summary-queue">自动配置</b></div><div><span>登录会话</span><b id="summary-credential">未登录</b></div></div>
<p class="connection-summary-note" id="summary-note">服务状态会自动检查;需要业务数据时再加载凭据。</p>
<button class="quiet-button" id="logout-inline" type="button">退出当前账号 <span>→</span></button>
</article>
</section>
</div>
<div class="page-view" id="view-tasks" data-page="tasks">
<section class="content-grid single-column">
<article class="panel wide-panel" id="tasks">
<div class="panel-heading"><div><span class="panel-kicker">PULSE / TASKS</span><h2>任务执行流</h2></div><div class="panel-tools"><span class="table-count" id="task-count">0 项</span><button class="text-button" data-view="overview">返回总览 <span>←</span></button></div></div>
<div class="table-wrap"><table><thead><tr><th>任务</th><th>应用 / 环境</th><th>处理器</th><th>状态</th><th>修订</th><th>创建时间</th></tr></thead><tbody id="task-table"><tr><td colspan="6" class="empty-row"><span class="empty-icon">◇</span><b>还没有任务数据</b><small>登录后按账号权限自动加载</small></td></tr></tbody></table></div>
</article>
</section>
</div>
<div class="page-view" id="view-schedules" data-page="schedules">
<section class="content-grid single-column">
<article class="panel" id="schedules"><div class="panel-heading"><div><span class="panel-kicker">PULSE / SCHEDULES</span><h2>定时计划</h2></div><span class="table-count" id="schedule-page-hint">点击计划查看详情</span></div><div class="schedule-list" id="schedule-list"><div class="empty-compact"><span>◷</span><div><b>等待计划数据</b><small>需要 schedules:read 权限</small></div></div></div></article>
</section>
</div>
<div class="page-view" id="view-workflows" data-page="workflows">
<section class="content-grid single-column">
<article class="panel" id="workflows"><div class="panel-heading"><div><span class="panel-kicker">WEAVE / WORKFLOWS</span><h2>流程实例</h2></div><span class="table-count">点击实例查看详情</span></div><div class="workflow-list" id="workflow-list"><div class="empty-compact"><span>⌘</span><div><b>等待流程数据</b><small>需要 workflows:read 权限</small></div></div></div></article>
</section>
</div>
<div class="page-view" id="view-subscriptions" data-page="subscriptions">
<section class="content-grid single-column">
<article class="panel" id="subscriptions"><div class="panel-heading"><div><span class="panel-kicker">EVENTS / DELIVERY</span><h2>结果订阅</h2></div><span class="live-label-small"><i></i>自动刷新</span></div><div class="subscription-list" id="subscription-list"><div class="empty-compact"><span>⌁</span><div><b>等待订阅数据</b><small>需要 events:read 权限</small></div></div></div></article>
</section>
</div>
<div class="page-view" id="view-archives" data-page="archives">
<div class="archive-heading"><div><span class="panel-kicker">DATA / ARCHIVE JOBS</span><h1>让历史数据,有序归档。</h1><p>配置周期,自动分批保存历史;每次执行都有进度与校验记录。</p></div><button class="secondary-button compact" id="archive-refresh">刷新作业 ↻</button></div>
<div class="archive-stats"><article><span>周期计划</span><strong id="archive-enabled-count">—</strong><small>已启用 / 7 个类别</small></article><article><span>本页待处理</span><strong id="archive-failed-count">—</strong><small>失败作业保留进度,等待处理</small></article><article><span>本页归档记录</span><strong id="archive-root-count">—</strong><small>数据库已确认的根记录数</small></article></div>
<div id="archive-error" class="action-error" role="alert"></div>
<section class="archive-grid">
<article class="panel archive-config">
<div class="panel-heading"><div><span class="panel-kicker">SCHEDULE</span><h2>周期配置</h2></div><span class="connection-state" id="archive-executor">正在读取</span></div>
<form id="archive-plan-form">
<label class="field-label" for="archive-kind">归档类别</label><select id="archive-kind"><option value="tasks">任务历史</option><option value="workflows">流程历史</option><option value="events">事件日志</option><option value="audit">管理审计</option><option value="deliveries">交付历史</option><option value="inbox">Inbox 历史</option><option value="idempotency">幂等记录</option></select>
<div class="retention-switch"><div><b>开启周期归档</b><small>首次启用立即运行,之后按周期执行。</small></div><label class="switch"><input id="archive-enabled" type="checkbox" aria-label="开启周期归档"><span></span></label></div>
<div class="archive-input-grid"><label for="archive-interval">执行间隔(小时)<input id="archive-interval" type="number" min="1" max="720" required></label><label for="archive-batch">每批根记录数<input id="archive-batch" type="number" min="1" max="100" required></label></div>
<label class="field-label" for="archive-budget">单作业容量上限(MiB)</label><input id="archive-budget" type="number" min="1" max="1024" required>
<div class="archive-plan-meta"><span id="archive-plan-revision">配置尚未保存</span><span id="archive-next-run">下次执行 —</span><span id="archive-policy-note"></span></div>
<label class="field-label" for="archive-reason">变更原因</label><input id="archive-reason" type="text" maxlength="1024" placeholder="说明本次周期配置的调整原因" required>
<button id="archive-plan-save" class="primary-button compact" type="submit">保存周期配置 <span>→</span></button>
<p class="panel-description" id="archive-plan-hint">归档使用已保存的保留策略。关闭周期只停止新作业,已有作业继续结清。</p>
</form>
<div class="archive-plan-chips" id="archive-plan-chips"></div>
<button class="text-button" data-view="retention">调整历史保留时间 ↗</button>
</article>
<article class="panel archive-history">
<div class="panel-heading"><div><span class="panel-kicker">EXECUTION HISTORY</span><h2>归档作业</h2></div><span class="table-count" id="archive-job-count">0 项</span></div>
<p class="panel-description">源数据库记录始终保留。文件写入服务端持久卷,页面展示已确认的批次和 SHA-256 摘要。</p>
<div class="archive-job-list" id="archive-job-list"><div class="empty-row">正在读取归档作业…</div></div>
<div class="archive-pager"><button class="secondary-button compact" id="archive-first">返回最新</button><button class="secondary-button compact" id="archive-next" disabled>更早作业 ↓</button></div>
<form id="archive-action-form" hidden>
<h3 id="archive-action-title">处理失败作业</h3><p class="panel-description" id="archive-action-note"></p>
<label class="field-label" for="archive-action-budget">单作业容量上限(MiB)</label><input id="archive-action-budget" type="number" min="1" max="1024" required>
<label class="field-label" for="archive-action-reason">处理原因</label><input id="archive-action-reason" type="text" maxlength="1024" placeholder="说明核查情况和处理原因" required>
<div class="action-form-buttons"><button id="archive-action-submit" type="submit" class="primary-button compact">确认处理</button><button id="archive-action-cancel" type="button" class="secondary-button compact">取消</button></div>
</form>
</article>
</section>
</div>
<div class="page-view" id="view-retention" data-page="retention">
<section class="content-grid single-column">
<article class="panel wide-panel retention-panel">
<div class="panel-heading"><div><span class="panel-kicker">DATA / RETENTION</span><h2>历史数据保留策略</h2></div><span class="connection-state ready" id="retention-source">默认策略</span></div>
<p class="panel-description">这里配置各类历史记录的最短保留时间。保存策略只记录配置,不会立即删除数据;预览和导出会核对终态与未确认结果。当前提供只读快照,不自动清理源数据。</p>
<div id="retention-scope" class="retention-scope"></div><form id="retention-form" class="retention-form">
<div class="retention-switch"><div><b>允许导出只读归档</b><small>默认关闭。开启并保存后,可分批导出已满足保留窗口的历史;未确认结果仍受保护。</small></div><label class="switch"><input id="retention-enabled" type="checkbox" aria-label="允许导出只读归档"><span></span></label></div>
<div class="retention-grid">
<label class="retention-field"><span>幂等记录</span><small>天</small><input id="retention-idempotency" type="number" min="90" max="3650" required></label>
<label class="retention-field"><span>任务历史</span><small>天</small><input id="retention-task" type="number" min="1" max="3650" required></label>
<label class="retention-field"><span>流程历史</span><small>天</small><input id="retention-workflow" type="number" min="1" max="3650" required></label>
<label class="retention-field"><span>事件日志</span><small>天</small><input id="retention-event" type="number" min="1" max="3650" required></label>
<label class="retention-field"><span>交付历史</span><small>天</small><input id="retention-delivery" type="number" min="1" max="3650" required></label>
<label class="retention-field"><span>Inbox 历史</span><small>天</small><input id="retention-inbox" type="number" min="1" max="3650" required></label>
<label class="retention-field retention-field-wide"><span>管理审计</span><small>天</small><input id="retention-audit" type="number" min="1" max="3650" required></label>
</div>
<div class="retention-meta"><span>当前版本 <b id="retention-revision">默认</b></span><span>最后修改 <b id="retention-updated">—</b></span></div>
<label class="field-label" for="retention-reason">变更原因</label>
<input id="retention-reason" class="retention-reason" type="text" maxlength="1024" placeholder="说明为什么调整历史保留窗口" required>
<div class="action-form-buttons"><button class="primary-button compact" id="retention-submit" type="submit">保存保留策略 <span>→</span></button></div>
<div class="retention-tools">
<label class="retention-select"><span>历史类型</span><select id="retention-kind"><option value="tasks">任务历史</option><option value="workflows">流程历史</option><option value="events">事件日志</option><option value="audit">管理审计</option><option value="deliveries">交付历史</option><option value="inbox">Inbox 历史</option><option value="idempotency">幂等记录</option></select></label>
<div class="retention-tool-buttons"><button class="secondary-button compact" id="retention-preview-button" type="button">预览候选</button><button class="secondary-button compact" id="retention-export-button" type="button">导出首批 ↓</button><button class="secondary-button compact" id="retention-restart-button" type="button" disabled>从首批开始</button></div>
</div>
<p class="panel-description" id="retention-export-hint"></p>
<div class="retention-export-result" aria-live="polite"><span id="retention-export-status">尚未导出</span><a id="retention-download" hidden>重新下载本批</a><code id="retention-export-sha"></code></div>
<div class="retention-preview" id="retention-preview" aria-live="polite"><span>保存策略后可预览当前窗口下的候选数据;预览不会删除任何记录。</span></div>
<div class="action-error" id="retention-error" role="alert"></div>
</form>
</article>
</section>
</div>
<div class="page-view" id="view-applications" data-page="applications">
<div class="access-heading"><div><span class="panel-kicker">CONNECT / APPLICATIONS</span><h1>让应用,轻松接入。</h1><p>创建应用、管理凭据,把任务交给正确的队列。</p></div><button class="primary-button compact" id="access-create">新建应用 <span>+</span></button></div>
<div class="access-guide"><span><b>01</b> 创建应用与队列</span><i>→</i><span><b>02</b> 复制 SDK 配置</span><i>→</i><span><b>03</b> 注册 Worker 开始执行</span></div>
<div id="access-error" class="action-error" role="alert"></div>
<section class="access-grid">
<article class="panel access-list-panel"><div class="panel-heading"><div><span class="panel-kicker">YOUR APPLICATIONS</span><h2>接入应用</h2></div><button class="text-button" id="access-refresh">刷新 ↻</button></div>
<div id="access-list" class="access-list"><p class="panel-description">正在读取应用…</p></div>
<div class="access-pager"><button class="text-button" id="access-first">第一页</button><button class="text-button" id="access-next" disabled>下一页 →</button></div>
</article>
<article class="panel access-detail-panel"><div id="access-empty" class="empty-row">选择应用,查看队列和接入配置。</div>
<div id="access-detail" hidden>
<div class="panel-heading"><div><span class="panel-kicker">APPLICATION DETAILS</span><h2 id="access-title"></h2></div><span class="connection-state" id="access-status"></span></div>
<div class="access-meta"><div><span>应用 ID</span><code id="access-app-id"></code></div><div><span>环境 / 命名空间</span><b id="access-scope"></b></div><div><span>命名空间 ID</span><code id="access-ns-id"></code></div></div>
<div class="access-config-grid"><label>服务地址<input id="access-url" type="url" autocomplete="off" spellcheck="false"></label><label>任务队列<select id="access-queue"></select></label></div>
<p class="panel-description">本机默认使用当前页面地址;容器内可填写 http://orbit-test:8080,部署后可换成服务域名。</p>
<div class="access-credentials" id="access-credentials"></div>
<p class="panel-description" id="access-truncated" hidden>队列或凭据超过 100 项,此页只展示前 100 项。</p>
<div class="access-config-heading"><h3>接入配置预览</h3><button class="text-button" id="access-copy-template">查看完整接入配置 ↗</button></div>
<p class="panel-description">预览默认隐藏 Token。点击「查看完整接入配置」,即可复制包含当前 Token 的配置,或下载 orbit.env。</p>
<pre class="access-code" id="access-config"></pre>
<div class="access-help">Token 确定应用和权限,队列决定任务去向。业务服务注册相同名称与版本的 handler 后,即可执行任务。</div>
</div>
</article>
</section>
</div>
<footer class="page-footer"><span><span class="footer-orbit">◉</span> Orbit Console · 星轨控制台</span><span>数据每 10 秒刷新 · <a href="/version" target="_blank" rel="noreferrer">查看服务版本</a></span></footer>
</main>
</div>
<div class="drawer-backdrop" id="task-drawer-backdrop" hidden>
<aside class="task-drawer" role="dialog" aria-modal="true" aria-labelledby="detail-title">
<div class="detail-scope"></div><div class="drawer-header">
<div><span class="panel-kicker">PULSE / TASK DETAIL</span><h2 id="detail-title">任务详情</h2><small class="drawer-id" id="detail-id">—</small></div>
<button class="icon-button" id="close-task-drawer" type="button" aria-label="关闭任务详情">×</button>
</div>
<div class="drawer-status-line"><span class="state-pill" id="detail-state">—</span><span id="detail-updated">—</span></div>
<div class="detail-grid">
<div><span>处理器</span><b id="detail-handler">—</b></div>
<div><span>修订</span><b id="detail-revision">—</b></div>
<div><span>执行尝试</span><b id="detail-attempt-count">—</b></div>
<div><span>效果状态</span><b id="detail-effect">—</b></div>
<div><span>创建时间</span><b id="detail-created">—</b></div>
<div><span>截止时间</span><b id="detail-deadline">—</b></div>
</div>
<div class="detail-block" id="detail-result-block" hidden><div class="detail-block-heading"><span>最终结果</span><small>只读快照</small></div><pre id="detail-result"></pre></div>
<div class="detail-block"><div class="detail-block-heading"><span>执行时间线</span><small id="detail-attempts-count">加载中</small></div><div class="detail-list" id="detail-attempts"><div class="detail-loading">正在读取尝试历史…</div></div></div>
<div class="detail-block"><div class="detail-block-heading"><span>操作审计</span><small id="detail-operations-count">加载中</small></div><div class="detail-list" id="detail-operations"><div class="detail-loading">正在读取操作审计…</div></div></div>
<div class="drawer-actions" id="detail-actions" hidden>
<button class="quiet-button danger-button" id="task-cancel-button" type="button">取消任务</button>
<button class="primary-button compact" id="task-retry-button" type="button">安全重试 <span>→</span></button>
</div>
<p class="drawer-note" id="detail-action-note">写操作需要对应的管理权限;服务端会再次校验版本、状态、幂等键和队列范围。</p>
<form class="action-form" id="task-action-form" hidden>
<div class="action-form-heading"><span class="panel-kicker" id="action-kicker">TASK CONTROL</span><h3 id="action-title">任务操作</h3></div>
<p id="action-description"></p>
<label class="field-label" for="action-reason">操作原因</label><textarea id="action-reason" rows="3" maxlength="1024" placeholder="说明本次操作的原因"></textarea>
<div id="action-evidence-wrap"><label class="field-label" for="action-evidence">证据引用</label><input id="action-evidence" type="text" maxlength="512" placeholder="例如 evidence:reconcile-001"></div>
<div id="action-timeout-wrap"><label class="field-label" for="action-timeout">新任务总时限(毫秒)</label><input id="action-timeout" type="number" min="1" max="2592000000" step="1" value="60000"></div>
<label class="check-row" id="action-safe-wrap"><input id="action-safe" type="checkbox"><span>我确认旧执行已经结束,按原业务身份重新执行是安全的。</span></label>
<div class="action-form-buttons"><button class="quiet-button" id="action-cancel" type="button">返回</button><button class="primary-button compact" id="action-submit" type="submit">提交操作 <span>→</span></button></div>
<div class="action-error" id="action-error" role="alert"></div>
</form>
</aside>
</div>
<div class="drawer-backdrop" id="schedule-drawer-backdrop" hidden>
<aside class="task-drawer schedule-drawer" role="dialog" aria-modal="true" aria-labelledby="schedule-detail-title">
<div class="detail-scope"></div><div class="drawer-header">
<div><span class="panel-kicker">PULSE / SCHEDULE DETAIL</span><h2 id="schedule-detail-title">定时计划</h2><small class="drawer-id" id="schedule-detail-id">—</small></div>
<button class="icon-button" id="close-schedule-drawer" type="button" aria-label="关闭计划详情">×</button>
</div>
<div class="drawer-status-line"><span class="state-pill" id="schedule-detail-state">—</span><span id="schedule-detail-updated">—</span></div>
<div class="detail-grid">
<div><span>计划名称</span><b id="schedule-detail-name">—</b></div>
<div><span>队列</span><b id="schedule-detail-queue">—</b></div>
<div><span>控制修订</span><b id="schedule-detail-revision">—</b></div>
<div><span>当前版本</span><b id="schedule-detail-version">—</b></div>
<div><span>下一次触发</span><b id="schedule-detail-next">—</b></div>
<div><span>时区</span><b id="schedule-detail-timezone">—</b></div>
</div>
<div class="detail-block"><div class="detail-block-heading"><span>当前版本规则</span><small id="schedule-detail-rule-kind">—</small></div><div class="schedule-rule-card" id="schedule-detail-rule">等待计划数据…</div></div>
<div class="detail-block"><div class="detail-block-heading"><span>最近触发记录</span><small id="schedule-occurrences-count">加载中</small></div><div class="detail-list" id="schedule-occurrences"><div class="detail-loading">正在读取触发记录…</div></div></div>
<div class="drawer-actions" id="schedule-actions" hidden><button class="quiet-button" id="schedule-control-button" type="button">暂停计划</button></div>
<p class="drawer-note" id="schedule-action-note">计划控制需要 schedules:manage 权限;暂停只停止未来触发,已经创建的任务继续执行。</p>
<form class="action-form" id="schedule-action-form" hidden>
<div class="action-form-heading"><span class="panel-kicker">SCHEDULE CONTROL</span><h3 id="schedule-action-title">暂停计划</h3></div>
<p id="schedule-action-description">暂停后不会再创建新的任务。</p>
<label class="field-label" for="schedule-action-reason">操作原因</label><textarea id="schedule-action-reason" rows="3" maxlength="1024" placeholder="说明本次计划控制的原因"></textarea>
<div class="action-form-buttons"><button class="quiet-button" id="schedule-action-cancel" type="button">返回</button><button class="primary-button compact" id="schedule-action-submit" type="submit">提交控制 →</button></div>
<div class="action-error" id="schedule-action-error" role="alert"></div>
</form>
</aside>
</div>
<div class="drawer-backdrop" id="workflow-drawer-backdrop" hidden>
<aside class="task-drawer workflow-drawer" role="dialog" aria-modal="true" aria-labelledby="workflow-detail-title">
<div class="detail-scope"></div><div class="drawer-header">
<div><span class="panel-kicker">WEAVE / WORKFLOW DETAIL</span><h2 id="workflow-detail-title">流程实例</h2><small class="drawer-id" id="workflow-detail-id">—</small></div>
<button class="icon-button" id="close-workflow-drawer" type="button" aria-label="关闭流程详情">×</button>
</div>
<div class="drawer-status-line"><span class="state-pill" id="workflow-detail-state">—</span><span id="workflow-detail-updated">—</span></div>
<div class="detail-grid">
<div><span>定义</span><b id="workflow-detail-definition">—</b></div>
<div><span>固定版本</span><b id="workflow-detail-version">—</b></div>
<div><span>实例修订</span><b id="workflow-detail-revision">—</b></div>
<div><span>控制修订</span><b id="workflow-detail-control-revision">—</b></div>
<div><span>业务键</span><b id="workflow-detail-business-key">—</b></div>
<div><span>总截止时间</span><b id="workflow-detail-deadline">—</b></div>
</div>
<div class="detail-block"><div class="detail-block-heading"><span>步骤状态</span><small id="workflow-steps-count">加载中</small></div><div class="detail-list" id="workflow-steps"><div class="detail-loading">正在读取步骤…</div></div></div>
<div class="detail-block"><div class="detail-block-heading"><span>事件时间线</span><small id="workflow-events-count">加载中</small></div><div class="detail-list" id="workflow-events"><div class="detail-loading">正在读取事件…</div></div></div>
<div class="detail-block" id="workflow-output-block" hidden><div class="detail-block-heading"><span>流程输出</span><small>只读快照</small></div><pre id="workflow-output"></pre></div>
<div class="detail-block recovery-block" id="workflow-recovery-block" hidden>
<div class="detail-block-heading"><span>人工核查与恢复</span><small id="workflow-recovery-hint">需要 workflows:recover</small></div>
<p class="recovery-intro">只在 NEEDS_REVIEW 状态显示。每个决定都要引用外部证据,并使用当前流程、步骤和激活修订;服务端会再次校验所有门控。</p>
<div class="recovery-action-grid" id="workflow-recovery-actions"></div>
</div>
<div class="drawer-actions" id="workflow-actions" hidden><button class="quiet-button" id="workflow-control-button" type="button">暂停流程</button><button class="quiet-button danger-button" id="workflow-cancel-button" type="button">取消流程</button></div>
<p class="drawer-note" id="workflow-detail-note">流程详情只读取当前权威视图;事件审计需要 workflows:audit:read 权限,所有控制操作仍由服务端权限和并发版本校验。</p>
<form class="action-form" id="workflow-action-form" hidden>
<div class="action-form-heading"><span class="panel-kicker">WEAVE CONTROL</span><h3 id="workflow-action-title">流程控制</h3></div>
<p id="workflow-action-description">流程控制会写入不可变审计,并使用当前控制修订进行并发校验。</p>
<label class="field-label" for="workflow-action-reason">操作原因</label><textarea id="workflow-action-reason" rows="3" maxlength="1024" placeholder="说明本次流程控制的原因"></textarea>
<div class="action-form-buttons"><button class="quiet-button" id="workflow-action-cancel" type="button">返回</button><button class="primary-button compact" id="workflow-action-submit" type="submit">提交控制 →</button></div>
<div class="action-error" id="workflow-action-error" role="alert"></div>
</form>
<form class="action-form recovery-form" id="workflow-recovery-form" hidden>
<div class="action-form-heading"><span class="panel-kicker">WEAVE RECOVERY</span><h3 id="workflow-recovery-title">人工恢复</h3></div>
<p id="workflow-recovery-description">提交后会写入流程审计,并按当前版本重新读取实例。</p>
<div class="recovery-snapshot" id="workflow-recovery-snapshot">当前流程修订 — · 当前步骤 —</div>
<label class="field-label" for="workflow-recovery-reason">核查原因</label><textarea id="workflow-recovery-reason" rows="3" maxlength="1024" placeholder="说明你核实了什么事实,以及为什么可以执行该决定"></textarea>
<label class="field-label" for="workflow-recovery-evidence">证据引用</label><input id="workflow-recovery-evidence" type="text" maxlength="512" placeholder="例如 evidence:query-001(不能含空格)">
<div id="workflow-recovery-step-fields" hidden>
<label class="field-label" for="workflow-recovery-step-key">步骤键</label><input id="workflow-recovery-step-key" type="text" maxlength="64" placeholder="当前步骤 key">
<label class="field-label" for="workflow-recovery-activation-id">激活 ID</label><input id="workflow-recovery-activation-id" type="text" maxlength="32" placeholder="当前激活代次 ID">
<label class="field-label" for="workflow-recovery-step-revision">步骤修订</label><input id="workflow-recovery-step-revision" type="number" min="1" step="1" placeholder="当前步骤 revision">
</div>
<div id="workflow-recovery-task-fields" hidden>
<label class="field-label" for="workflow-recovery-task-id">任务 ID</label><input id="workflow-recovery-task-id" type="text" maxlength="32" placeholder="待核查任务 ID">
<label class="field-label" for="workflow-recovery-task-revision">任务修订</label><input id="workflow-recovery-task-revision" type="number" min="1" step="1" placeholder="当前任务 revision">
</div>
<div class="recovery-inline-fields" id="workflow-recovery-outcome-fields" hidden>
<div><label class="field-label" for="workflow-recovery-outcome">结论</label><select id="workflow-recovery-outcome"><option value="SUCCEEDED">SUCCEEDED · 成功</option><option value="FAILED">FAILED · 失败</option></select></div>
<div id="workflow-recovery-result-wrap"><label class="field-label" for="workflow-recovery-result">结果 JSON</label><textarea id="workflow-recovery-result" rows="3" placeholder="例如 {&quot;status&quot;:&quot;DONE&quot;};TIMER 成功可填 null"></textarea></div>
</div>
<label class="check-row" id="workflow-recovery-confirm-row"><input id="workflow-recovery-confirm" type="checkbox"><span id="workflow-recovery-confirm-label">我确认已核实当前事项,可以提交这个恢复决定。</span></label>
<div class="action-form-buttons"><button class="quiet-button" id="workflow-recovery-cancel" type="button">返回</button><button class="primary-button compact" id="workflow-recovery-submit" type="submit">提交恢复 →</button></div>
<div class="action-error" id="workflow-recovery-error" role="alert"></div>
</form>
</aside>
</div>
<div class="drawer-backdrop" id="subscription-drawer-backdrop" hidden>
<aside class="task-drawer subscription-drawer" role="dialog" aria-modal="true" aria-labelledby="subscription-detail-title">
<div class="detail-scope"></div><div class="drawer-header">
<div><span class="panel-kicker">EVENTS / SUBSCRIPTION DETAIL</span><h2 id="subscription-detail-title">结果订阅</h2><small class="drawer-id" id="subscription-detail-id">—</small></div>
<button class="icon-button" id="close-subscription-drawer" type="button" aria-label="关闭订阅详情">×</button>
</div>
<div class="drawer-status-line"><span class="state-pill" id="subscription-detail-state">—</span><span id="subscription-detail-updated">—</span></div>
<div class="detail-grid">
<div><span>订阅名称</span><b id="subscription-detail-name">—</b></div>
<div><span>队列</span><b id="subscription-detail-queue">—</b></div>
<div><span>配置修订</span><b id="subscription-detail-revision">—</b></div>
<div><span>待确认交付</span><b id="subscription-detail-pending">—</b></div>
<div><span>未确认上限</span><b id="subscription-detail-max-pending">—</b></div>
<div><span>单条次数预算</span><b id="subscription-detail-max-attempts">—</b></div>
<div><span>游标序号</span><b id="subscription-detail-cursor">—</b></div>
<div><span>事件类型</span><b id="subscription-detail-types">—</b></div>
</div>
<div class="detail-block"><div class="detail-block-heading"><span>最近交付</span><small id="subscription-deliveries-count">加载中</small></div><div class="detail-list" id="subscription-deliveries"><div class="detail-loading">正在读取交付历史…</div></div></div>
<div class="drawer-actions" id="subscription-actions" hidden><button class="quiet-button" id="subscription-control-button" type="button">暂停订阅</button></div>
<p class="drawer-note" id="subscription-detail-note">交付详情不展示租约秘密;结果确认与人工重试必须通过受保护的消费或管理接口完成。</p>
<form class="action-form" id="subscription-action-form" hidden>
<div class="action-form-heading"><span class="panel-kicker">EVENTS CONTROL</span><h3 id="subscription-action-title">订阅控制</h3></div>
<p id="subscription-action-description">订阅控制会保留已有交付和审计记录。</p>
<label class="field-label" for="subscription-action-reason">操作原因</label><textarea id="subscription-action-reason" rows="3" maxlength="1024" placeholder="说明本次订阅控制的原因"></textarea>
<div class="action-form-buttons"><button class="quiet-button" id="subscription-action-cancel" type="button">返回</button><button class="primary-button compact" id="subscription-action-submit" type="submit">提交控制 →</button></div>
<div class="action-error" id="subscription-action-error" role="alert"></div>
</form>
<form class="action-form" id="subscription-retry-form" hidden>
<div class="action-form-heading"><span class="panel-kicker">EVENTS RECOVERY</span><h3>重试过期交付</h3></div>
<p>只允许对 EXPIRED 交付追加次数预算;原交付身份、已用次数和事件不会重置。</p>
<label class="field-label" for="subscription-retry-reason">操作原因</label><textarea id="subscription-retry-reason" rows="3" maxlength="1024" placeholder="说明接收方已修复的原因"></textarea>
<label class="field-label" for="subscription-retry-attempts">追加次数(1–100)</label><input id="subscription-retry-attempts" type="number" min="1" max="100" step="1" value="1">
<div class="action-form-buttons"><button class="quiet-button" id="subscription-retry-cancel" type="button">返回</button><button class="primary-button compact" id="subscription-retry-submit" type="submit">追加预算并重试 →</button></div>
<div class="action-error" id="subscription-retry-error" role="alert"></div>
</form>
</aside>
</div>
<div class="toast" id="toast" role="status"></div>
<dialog id="access-dialog" class="access-dialog">
<div class="access-dialog-top"><span class="panel-kicker">ORBIT / CONNECT</span><button type="button" class="icon-button" id="access-close" aria-label="关闭应用接入">×</button></div>
<h2 id="access-form-title">新建应用</h2><p class="panel-description" id="access-form-note">为应用创建独立的环境、队列与调用凭据。</p>
<p class="access-token-once-note" id="access-token-once-note">Token 会加密保存。管理员可随时查看接入信息、复制完整配置或下载 orbit.env。</p>
<form id="access-form">
<div id="access-create-fields">
<label>应用名称<input id="access-name" maxlength="128" placeholder="例如 order-service" autocomplete="off" required pattern="[A-Za-z0-9][A-Za-z0-9_.:\-]*"></label>
<div class="access-config-grid"><label>环境<select id="access-environment"><option value="test">测试 · test</option><option value="development">开发 · development</option><option value="production">生产 · production</option></select></label><label>命名空间<input id="access-namespace" value="default" maxlength="128" required pattern="[A-Za-z0-9][A-Za-z0-9_.:\-]*"></label></div>
<label>初始队列名称<input id="access-queue-name" value="default" maxlength="128" required pattern="[A-Za-z0-9][A-Za-z0-9_.:\-]*"></label>
<fieldset class="access-capabilities"><legend>接入能力 <small>默认包含任务提交、查询与队列管理</small></legend><label><input type="checkbox" value="worker" checked> Worker 执行</label><label><input type="checkbox" value="events" checked> 结果订阅</label><label><input type="checkbox" value="schedules" checked> 定时调度</label><label><input type="checkbox" value="workflows" checked> 流程编排</label><label><input type="checkbox" value="recovery"> 人工恢复</label><label><input type="checkbox" value="resources"> 应用额度管理</label></fieldset>
</div>
<div class="access-config-grid"><label id="access-valid-field">凭据有效期<select id="access-valid-days"><option value="0">长期有效</option><option value="30">30 天</option><option value="90">90 天</option><option value="365">365 天</option></select></label><label>操作原因<input id="access-reason" maxlength="1024" required placeholder="例如:接入订单服务"></label></div>
<label id="access-grace-field" hidden>旧 Token 过渡期<select id="access-grace-days"><option value="7">7 天</option><option value="1">1 天</option><option value="30">30 天</option></select><small>新旧 Token 同时可用。请在截止前完成所有服务的配置更新;旧 Token 原到期时间更早时,以原到期时间为准。</small></label>
<p class="action-error" id="access-form-error" role="alert"></p>
<div class="access-form-actions"><button type="submit" class="primary-button compact" id="access-submit">创建并生成凭据 →</button><button type="button" class="text-button" id="access-backup" hidden>保存待核对操作</button></div>
</form>
<p id="access-clipboard-status" class="panel-description" role="status"></p>
<section id="access-result" hidden><div class="access-success">✓ <span id="access-result-title">应用已创建</span></div><p class="access-token-once-note" id="access-result-note">复制下面的完整接入配置即可用于业务服务。关闭后仍可从凭据卡片的「查看接入信息」重新获取当前 Token。</p><label id="access-result-config-field">完整 SDK 配置<textarea id="access-result-config" readonly rows="7" spellcheck="false"></textarea></label><p class="panel-description" id="access-result-expiry"></p><div class="access-form-actions" id="access-result-actions"><button type="button" class="primary-button compact" id="access-copy">复制配置 ↗</button><button type="button" class="secondary-button compact" id="access-download">下载 .env ↓</button></div></section>
</dialog>
<dialog id="access-help-dialog" class="access-dialog access-credential-help" aria-labelledby="access-help-title">
<div class="access-dialog-top"><span class="panel-kicker">ORBIT / CREDENTIAL</span><button type="button" class="icon-button" id="access-help-close" aria-label="关闭凭据说明">×</button></div>
<h2 id="access-help-title">凭据与换证说明</h2>
<p class="panel-description" id="access-help-scope"></p>
<div class="access-rotation-notice"><strong>当前换证状态</strong><p id="access-help-state"></p></div>
<h3>查看和复制当前接入配置</h3>
<p>在凭据卡片点击「查看接入信息」或「复制接入配置」。配置包含服务地址、应用 ID、命名空间、队列和当前 Token;换证过渡期也可以获取。</p>
<div id="access-help-transition" hidden><p>当前新 Token 可以正常查看和复制。确认所有服务已切换、在途任务已收尾后,再结束旧 Token 过渡。</p></div>
<div class="access-form-actions"><button type="button" class="primary-button compact" id="access-help-done">我知道了</button></div>
</dialog>
<dialog id="access-token-dialog" class="access-dialog" aria-labelledby="access-token-title">
<div class="access-dialog-top"><span class="panel-kicker">ORBIT / INTEGRATION</span><button type="button" class="icon-button" id="access-token-close" aria-label="关闭接入信息">×</button></div>
<h2 id="access-token-title">接入信息</h2><p class="panel-description" id="access-token-scope"></p>
<form id="access-token-import" hidden>
<p class="panel-description">此凭据创建于 Token 保管功能启用之前。导入已保存的当前 Token 后,管理员即可随时查看和复制完整配置。导入不会换证,也不会改变有效期或过渡时间。</p>
<label>当前 Token<input id="access-token-input" type="password" autocomplete="off" spellcheck="false" maxlength="512" required placeholder="粘贴当前 ORBIT_TOKEN"></label>
<button type="submit" class="primary-button compact" id="access-token-import-submit">导入并查看接入配置 →</button>
</form>
<section id="access-token-output" hidden>
<label>完整接入配置<textarea id="access-token-config" readonly rows="8" spellcheck="false" autocomplete="off"></textarea></label>
<p class="panel-description">按所选服务地址和授权队列生成,包含当前 Token。可以直接粘贴到业务服务的环境配置中。</p>
<div class="access-form-actions"><button type="button" class="primary-button compact" id="access-token-copy">复制接入配置 ↗</button><button type="button" class="secondary-button compact" id="access-token-download">下载 orbit.env ↓</button></div>
</section>
<p class="action-error" id="access-token-error" role="status"></p>
</dialog>
<script src="/console/applications.js"></script>
<script src="/console/app.js"></script>
</body>
</html>