测试处方上传

This commit is contained in:
李琦
2026-06-05 16:36:47 +08:00
parent 16aebb45b6
commit bf816536be

View File

@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>处方/核销联调</title>
<link rel="stylesheet" href="/static/static.css">
<style>
.step-block { margin-bottom: 2rem; }
.step-block h2 { margin: 0 0 0.5rem; font-size: 1.15rem; }
.muted-note { color: var(--muted); font-size: 0.88rem; margin: 0 0 0.75rem; }
.result-panel { margin-top: 0.75rem; }
.result-panel h4 { margin: 0.75rem 0 0.25rem; font-size: 0.9rem; color: var(--accent); }
.result-panel pre { margin: 0 0 0.5rem; max-height: 14rem; overflow: auto; font-size: 0.82rem; }
</style>
</head>
<body>
<div class="wrap">
<header>
<h1>处方上传 / 处方核销联调</h1>
<nav class="nav" id="main-nav"></nav>
</header>
<p class="muted-note">与 Cron/CLI 自动同步共用 <code>executeStep</code>(开头刷新 token/config → 拉取 → 组包签名上报 → 批量回调)。默认每条 step 只处理 <b>1</b> 条;对比验收可设 limit=0。</p>
<div class="step-block" id="block-recipe">
<h2>测试在线处方上传</h2>
<div class="toolbar">
<label>锚定日 <input type="date" id="date-recipe"></label>
<label>条数 limit
<input type="number" id="limit-recipe" min="0" value="1" style="width:4rem" title="0=全部">
</label>
<button class="primary" id="run-recipe">执行</button>
</div>
<div class="result-panel" id="out-recipe"><pre>尚未执行</pre></div>
</div>
<div class="step-block" id="block-verification">
<h2>测试处方核销</h2>
<div class="toolbar">
<label>锚定日 <input type="date" id="date-verification"></label>
<label>条数 limit
<input type="number" id="limit-verification" min="0" value="1" style="width:4rem">
</label>
<button class="primary" id="run-verification">执行</button>
</div>
<div class="result-panel" id="out-verification"><pre>尚未执行</pre></div>
</div>
</div>
<script src="/static/app.js"></script>
<script>
if (typeof renderMainNav === 'function') renderMainNav('supervise-step');
function renderStepResult(data) {
if (!data) return '(无数据)';
const lines = [];
lines.push('step: ' + (data.step_label || data.step) + ' anchor: ' + data.anchor_date + ' batch_id: ' + data.batch_id);
if (data.pull_summary) {
const p = data.pull_summary;
lines.push('拉取: total=' + p.total + ' validation_failed=' + p.validation_failed + ' processed=' + p.processed);
}
if (data.summary) {
const s = data.summary;
lines.push('结果: success=' + s.success + ' failed=' + s.failed + ' skipped=' + s.skipped);
}
if (data.callback_error) {
lines.push('callback_error: ' + data.callback_error);
}
if (!data.items || !data.items.length) {
lines.push('(无业务条)');
return lines.join('\n') + '\n\n' + JSON.stringify(data, null, 2);
}
data.items.forEach((it, i) => {
lines.push('\n--- 记录 #' + (i + 1) + ' biz_key=' + (it.biz_key || '-') + ' ---');
if (it.validation_errors && it.validation_errors.length) {
lines.push('validation_errors: ' + JSON.stringify(it.validation_errors));
}
if (it.payload_snapshot) {
lines.push('\n[组包 payload 快照]\n' + it.payload_snapshot);
}
if (it.push_plain_json) {
lines.push('\n[推送明文 push_plain_json]\n' + it.push_plain_json);
}
const fu = it.recipe_file_upload;
if (fu) {
lines.push('\n[文件上传 28211]\n' + JSON.stringify(fu, null, 2));
}
if (it.push_headers) {
lines.push('\n[推送头 push_headers]\n' + JSON.stringify(it.push_headers, null, 2));
}
if (it.push) {
lines.push('\n[政务云上报]\n' + JSON.stringify(it.push, null, 2));
}
if (it.callback) {
lines.push('\n[云端回调 CallbackItem]\n' + JSON.stringify(it.callback, null, 2));
}
});
return lines.join('\n');
}
async function runStep(step, dateEl, limitEl, outEl, btn) {
const date = dateEl.value;
const limit = parseInt(limitEl.value, 10);
const body = { step, date, limit: isNaN(limit) ? 1 : limit };
btn.disabled = true;
outEl.innerHTML = '<pre>执行中…(开头会 ReloadCloudConfig</pre>';
try {
const r = await fetch('/api/supervise/step-test', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const j = await r.json().catch(() => ({}));
if (!r.ok) {
const text = (j.result ? renderStepResult(j.result) + '\n\n错误: ' : '') + (j.error || r.statusText);
outEl.innerHTML = '<pre>' + esc(text) + '</pre>';
showToast(firstLine(j.error || text), 'err');
return;
}
outEl.innerHTML = '<pre>' + esc(renderStepResult(j)) + '</pre>';
showToast('完成 step=' + step, 'ok');
} catch (e) {
outEl.innerHTML = '<pre>' + esc(e.message) + '</pre>';
showToast(e.message, 'err');
} finally {
btn.disabled = false;
}
}
const dateRecipe = document.getElementById('date-recipe');
const dateVer = document.getElementById('date-verification');
document.getElementById('run-recipe').onclick = () =>
runStep('recipe', dateRecipe, document.getElementById('limit-recipe'), document.getElementById('out-recipe'), document.getElementById('run-recipe'));
document.getElementById('run-verification').onclick = () =>
runStep('verification', dateVer, document.getElementById('limit-verification'), document.getElementById('out-verification'), document.getElementById('run-verification'));
</script>
</body>
</html>