Files
xk-hy-transit-go/internal/logweb/web/runs.html
2026-05-27 08:18:07 +08:00

140 lines
5.2 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">
<title>同步流水</title>
<link rel="stylesheet" href="/static/static.css">
</head>
<body>
<div class="wrap">
<header>
<h1>同步流水</h1>
<nav class="nav"><a href="/">首页</a><a href="/logs">文件日志</a><a href="/test">测试</a></nav>
</header>
<div class="toolbar">
<label>锚定日 <input type="date" id="anchor"></label>
<label>类型
<select id="step"></select>
</label>
<button class="primary" id="load">刷新</button>
<button type="button" class="danger" id="truncate" title="清空本机三表全部数据">清空三表</button>
</div>
<h3 style="color:var(--muted);font-size:0.95rem">同步任务</h3>
<div style="overflow:auto;margin-bottom:1.5rem">
<table><thead><tr>
<th>日期</th><th>类型</th><th>状态</th><th>总数</th><th>成功</th><th>失败</th><th>开始</th><th>结束</th>
</tr></thead><tbody id="jobs"></tbody></table>
</div>
<h3 style="color:var(--muted);font-size:0.95rem">业务记录(拉取 → 上报 → 回调)</h3>
<div style="overflow:auto">
<table><thead><tr>
<th>ID</th><th>日期</th><th>类型</th><th>批次</th><th>biz_key</th><th>拉取校验</th>
<th>上报</th><th>推送明文</th><th>HTTP</th><th>回调</th><th>trace</th><th></th>
</tr></thead><tbody id="items"></tbody></table>
</div>
</div>
<script src="/static/app.js"></script>
<script>
const anchorFromUrl = qs('anchor_date');
if (anchorFromUrl) document.getElementById('anchor').value = anchorFromUrl;
const truncateBtn = document.getElementById('truncate');
let pageMeta = null;
function updateTruncateButton(meta, syncRunning) {
if (!truncateBtn) return;
if (!meta || !meta.allowTruncate) {
truncateBtn.disabled = true;
truncateBtn.title = 'MySQL 未连接,无法清空';
return;
}
if (syncRunning) {
truncateBtn.disabled = true;
truncateBtn.title = '同步任务执行中,请稍后再试';
return;
}
truncateBtn.disabled = false;
truncateBtn.title = '清空本机 hy_push_log / hy_push_record / hy_sync_job不可恢复';
}
(async () => {
pageMeta = await loadMeta();
if (pageMeta && pageMeta.stepOptions) fillStepSelect(document.getElementById('step'), pageMeta.stepOptions);
updateTruncateButton(pageMeta, false);
})();
async function refreshSyncGate() {
try {
const s = await api('/api/test/status');
updateTruncateButton(pageMeta, !!(s && s.running));
} catch (_) {
/* ignore */
}
}
setInterval(refreshSyncGate, 2000);
async function load() {
const anchor = document.getElementById('anchor').value;
const step = document.getElementById('step').value;
let url = '/api/runs?limit=100';
if (anchor) url += '&anchor_date=' + anchor;
if (step) url += '&step=' + step;
const data = await api(url);
document.getElementById('jobs').innerHTML = (data.jobs || []).map(j => `<tr>
<td>${esc(j.anchorDate)}</td>
<td>${esc(j.stepLabel || j.step)}</td>
<td>${badge(j.status, j.statusLabel)}</td>
<td>${j.totalCount}</td><td>${j.successCount}</td><td>${j.failedCount}</td>
<td>${fmtTimeAny(j.startedAt)}</td>
<td>${fmtTimeAny(j.finishedAt)}</td>
</tr>`).join('') || '<tr><td colspan="8">无任务</td></tr>';
document.getElementById('items').innerHTML = (data.items || []).map(it => {
const r = it.record;
const cb = it.callback;
const ve = it.errors && it.errors.valid ? (it.errors.formatted || it.errors.raw) : (it.errors && it.errors.raw) || '';
const veShort = ve.length > 80 ? ve.slice(0, 80) + '…' : ve;
const ll = r.LastLog;
return `<tr>
<td>${r.ID}</td>
<td>${esc(r.AnchorDate)}</td>
<td>${esc(it.stepLabel || it.step)}</td>
<td>${r.JobID}</td>
<td><code>${esc(r.BizKey)}</code></td>
<td>${veShort ? '<span class="badge warn">有</span> ' + esc(veShort) : badge('success', '通过')}</td>
<td>${badge(r.PushStatus, it.pushStatusLabel)}</td>
<td>${it.hasPushPlain ? '<span class="badge ok">有</span>' : '<span class="badge warn">无</span>'}</td>
<td>${ll ? ll.HTTPCode + ' / ' + (ll.MsgCode && ll.MsgCode.Valid ? ll.MsgCode.Int64 : '-') + ' / ' + ll.DurationMs + 'ms' : '-'}</td>
<td>${badge(cb.callback_status, it.callbackStatusLabel)} ${esc(cb.error_message || '')}</td>
<td>${ll ? esc(ll.TraceID) : '-'}</td>
<td><a href="/runs/record?id=${r.ID}">详情</a></td>
</tr>`;
}).join('') || '<tr><td colspan="12">无记录</td></tr>';
}
document.getElementById('load').onclick = () => load().catch(e => alert(e.message));
truncateBtn.onclick = async () => {
const tables = 'hy_push_log、hy_push_record、hy_sync_job';
if (!confirm('将清空本机审计库三表(' + tables + '),不可恢复。\n仅影响本机 xk_hy_transit不动云端数据。\n\n确定继续')) return;
const typed = prompt('请输入 TRUNCATE 以确认清空:');
if (typed !== 'TRUNCATE') {
if (typed !== null) alert('已取消:确认词不正确');
return;
}
try {
await api('/api/runs/truncate', { method: 'POST' });
alert('三表已清空');
await load();
} catch (e) {
alert(e.message);
}
};
load().catch(e => alert(e.message));
refreshSyncGate();
</script>
</body>
</html>