Files
xk-hy-forward-go/internal/forward/testweb/web/prescription.js
2026-07-21 16:35:46 +08:00

133 lines
5.0 KiB
JavaScript
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.
(function () {
const state = { bizType: 'pdf', items: [], currentRel: null };
function $(id) { return document.getElementById(id); }
async function api(path, opts) {
const r = await fetch(path, opts);
const t = await r.text();
let j;
try { j = JSON.parse(t); } catch { j = { error: t }; }
if (!r.ok) throw new Error(j.error || r.statusText);
return j;
}
function esc(s) {
const d = document.createElement('div');
d.textContent = s == null ? '' : String(s);
return d.innerHTML;
}
function showToast(msg, ok) {
const el = $('toast');
el.textContent = msg;
el.className = 'rx-toast ' + (ok ? 'ok' : 'err');
setTimeout(() => { el.textContent = ''; el.className = 'rx-toast'; }, 4000);
}
function statusBadge(rec) {
if (rec.ok) return '<span class="badge ok">成功</span>';
return '<span class="badge err">失败</span>';
}
function fmtTime(at) {
if (!at) return '-';
try {
return new Date(at).toLocaleString('zh-CN');
} catch {
return esc(at);
}
}
async function load() {
const data = await api('/t/api/prescription/records?bizType=' + encodeURIComponent(state.bizType) + '&limit=200');
state.items = data.items || [];
const tb = $('tbody');
if (!state.items.length) {
tb.innerHTML = '<tr><td colspan="9" style="text-align:center;color:var(--muted)">暂无记录(可先触发同步或点「重建索引」)</td></tr>';
$('hint').textContent = '索引文件api-logs/prescription-audit.jsonl';
return;
}
tb.innerHTML = state.items.map((rec) => {
const hint = rec.fileId || rec.prescriptionHint || '-';
const rowClass = rec.ok ? '' : ' class="rx-fail"';
return '<tr' + rowClass + '>' +
'<td>' + fmtTime(rec.at) + '</td>' +
'<td><code>' + esc(rec.channel) + '</code></td>' +
'<td>' + esc(rec.httpStatus) + '</td>' +
'<td>' + esc(rec.msgCode != null ? rec.msgCode : '-') + '</td>' +
'<td><code class="trace">' + esc(rec.traceId || '-') + '</code></td>' +
'<td>' + esc(hint) + '</td>' +
'<td>' + statusBadge(rec) + (rec.errorSummary ? ' ' + esc(rec.errorSummary) : '') + '</td>' +
'<td>' + esc(rec.durationMs) + 'ms</td>' +
'<td class="rx-actions">' +
'<button type="button" class="btn sm" data-act="detail" data-rel="' + esc(rec.rel) + '">详情</button> ' +
'<button type="button" class="btn sm primary" data-act="retry" data-rel="' + esc(rec.rel) + '">重试</button>' +
'</td></tr>';
}).join('');
$('hint').textContent = '共 ' + state.items.length + ' 条 · 类型 ' + state.bizType;
tb.querySelectorAll('button[data-act]').forEach((btn) => {
btn.onclick = () => {
const rel = btn.dataset.rel;
if (btn.dataset.act === 'detail') openDetail(rel);
else retryRecord(rel);
};
});
}
async function openDetail(rel) {
state.currentRel = rel;
const d = await api('/t/api/logs/detail?rel=' + encodeURIComponent(rel));
$('detail-view').textContent = JSON.stringify(d, null, 2);
$('replay-view').style.display = 'none';
$('replay-view').textContent = '';
$('drawer').hidden = false;
}
async function retryRecord(rel) {
if (!confirm('向政务云回放该条出站请求块2\n\n注意仅内网运维重放不会更新 transit/xk-api 状态。')) return;
state.currentRel = rel;
try {
const result = await api('/t/api/test/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ rel: rel, useOutbound: true }),
});
$('replay-view').style.display = 'block';
$('replay-view').textContent = '回放结果:\n' + JSON.stringify(result, null, 2);
$('drawer').hidden = false;
$('detail-view').textContent = '(重试完成,见下方回放结果;可点详情查看完整 api-log)';
showToast('回放完成 HTTP ' + (result.httpStatus || '-'), result.ok !== false);
} catch (e) {
showToast(e.message, false);
}
}
document.querySelectorAll('.rx-tabs .tab').forEach((tab) => {
tab.onclick = () => {
document.querySelectorAll('.rx-tabs .tab').forEach((t) => t.classList.remove('active'));
tab.classList.add('active');
state.bizType = tab.dataset.biz;
load().catch((e) => showToast(e.message, false));
};
});
$('btn-refresh').onclick = () => load().catch((e) => showToast(e.message, false));
$('btn-rebuild').onclick = async () => {
if (!confirm('扫描 api-logs 全量重建 prescription-audit.jsonl')) return;
try {
const r = await api('/t/api/prescription/rebuild', { method: 'POST' });
showToast('已索引 ' + r.count + ' 条', true);
await load();
} catch (e) {
showToast(e.message, false);
}
};
$('btn-close-drawer').onclick = () => { $('drawer').hidden = true; };
$('btn-retry').onclick = () => {
if (state.currentRel) retryRecord(state.currentRel);
};
load().catch((e) => showToast(e.message, false));
})();