:root{
–bg:#ffffff;–fg:#111827;–muted:#6b7280;–brand:#2563eb;–brand-2:#1d4ed8;
–card:#f8fafc;–border:#e5e7eb;–ok:#16a34a;–warn:#b45309;–err:#dc2626;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;background:var(–bg);color:var(–fg);font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Apple Color Emoji,Noto Color Emoji,Arial,sans-serif;}
.wrap{max-width:980px;margin:32px auto;padding:0 16px 64px}
h1{font-size:clamp(22px,4vw,28px);margin:0 0 12px}
p.lead{color:var(–muted);margin:0 0 20px;line-height:1.6}
.card{background:var(–card);border:1px solid var(–border);border-radius:16px;padding:16px;margin:14px 0}
.grid{display:grid;gap:12px}
.g2{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}
label{font-weight:600;font-size:14px;display:block;margin:4px 0}
input,select,button,textarea{font:inherit}
input[type=”number”], input[type=”text”], select{
width:100%;padding:10px 12px;border:1px solid var(–border);border-radius:10px;background:#fff
}
.btn{display:inline-flex;align-items:center;gap:8px;border-radius:10px;border:1px solid var(–border);padding:10px 14px;background:#fff;cursor:pointer}
.btn.brand{background:var(–brand);border-color:var(–brand-2);color:#fff}
.btn.ghost{background:#fff}
.btn.warn{background:#fff5e5;border-color:#fed7aa;color:#9a3412}
.btn:disabled{opacity:.55;cursor:not-allowed}
.row{display:flex;gap:10px;flex-wrap:wrap}
.pill{display:inline-flex;gap:6px;align-items:center;padding:6px 10px;border-radius:999px;background:#eef2ff;border:1px solid #e0e7ff;color:#3730a3;font-size:12px}
.muted{color:var(–muted)}
.hr{height:1px;background:var(–border);margin:16px 0}
.med-row{display:grid;grid-template-columns:1.2fr 1fr .9fr auto;gap:8px;align-items:center}
.med-row .remove{padding:8px 10px;border-radius:8px;border:1px solid var(–border);background:#fff;cursor:pointer}
.right{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.result{font-size:15px;line-height:1.7}
.result .big{font-size:clamp(22px,4vw,32px);font-weight:800}
.tag{display:inline-block;margin-right:8px;color:#374151;background:#f3f4f6;border:1px solid #e5e7eb;border-radius:8px;padding:4px 8px;font-size:12px}
details summary{cursor:pointer;font-weight:700}
.note{font-size:12px;color:#6b7280}
.kbd{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;background:#f3f4f6;border:1px solid #e5e7eb;border-bottom-width:2px;padding:2px 6px;border-radius:6px}
.footer{font-size:12px;color:#6b7280}
@media (max-width:580px){.med-row{grid-template-columns:1fr}}
혈압 치료 효능 간편 계산기 (교육용)
두 가지 이상 약을 함께 쓸 때, 예상 수축기 혈압(SBP) 강하와 대략적 심혈관 위험 상대감소(경험칙: 1mmHg ↓ ≈ 위험 2% ↓)를 추정합니다. 실제 진료는 담당의사의 판단이 우선입니다.
가정(모형) 설명 보기
표준용량 1제 단독요법의 평균 SBP 강하(메타분석 기반, 대략치):
ACE 억제제 ≈ 8.5
ARB ≈ 8.0
칼슘채널차단제 ≈ 9.0
티아지드계 ≈ 10.0
베타차단제 ≈ 7.0
MRA(스피로노락톤 등) ≈ 10.0
기타 ≈ 6.0
용량 보정(대략치): 저용량 0.7×, 표준 1.0×, 고용량 1.2×. 서로 다른 계열은 효과가 대체로 가산된다고 가정합니다. 실제 환자별 반응, 병용 금기, 신·전해질 상태에 따른 제한 등은 반영하지 않습니다.
상단 입력과 약물을 추가한 뒤 계산하기를 눌러 주세요.
;(()=>{
// —————— 가정 파라미터 ——————
const POTENCY = {
‘ACE 억제제’: 8.5,
‘ARB’: 8.0,
‘칼슘채널차단제(CCB)’: 9.0,
‘티아지드/티아지드계’: 10.0,
‘베타차단제’: 7.0,
‘MRA(스피로노락톤 등)’: 10.0,
‘기타/중추성/혈관확장제’: 6.0,
};
const DOSE_MULT = {
‘저용량(¼~½)’: 0.7,
‘표준용량(1×)’: 1.0,
‘고용량(2×)’: 1.2,
};
// ————– DOM 참조 ————–
const elBaselineSbp = document.getElementById(‘baselineSbp’);
const elBaselineRisk = document.getElementById(‘baselineRisk’);
const elMedContainer = document.getElementById(‘medContainer’);
const elAddMed = document.getElementById(‘addMed’);
const elReset = document.getElementById(‘reset’);
const elCalc = document.getElementById(‘calcBtn’);
const elResult = document.getElementById(‘result’);
const elCopy = document.getElementById(‘copyBtn’);
const elPrint = document.getElementById(‘printBtn’);
// 초기 2행 제공
for(let i=0;iwindow.print());
function addMedRow(){
const row = document.createElement(‘div’);
row.className = ‘med-row’;
row.innerHTML = `
${Object.keys(POTENCY).map(k=>`${k}`).join(”)}
${Object.keys(DOSE_MULT).map(k=>`${k}`).join(”)}
`;
row.querySelector(‘.remove’).addEventListener(‘click’, ()=>{
row.remove();
liveCompute();
});
elMedContainer.appendChild(row);
liveCompute();
}
function resetAll(){
elBaselineSbp.value = ”;
elBaselineRisk.value = ”;
elMedContainer.innerHTML=”;
for(let i=0;i<2;i++) addMedRow();
elResult.innerHTML = '
상단 입력과 약물을 추가한 뒤 계산하기를 눌러 주세요.
‘;
}
function parseNum(v){
if(v===undefined||v===null) return NaN;
return Number(String(v).replace(/[^0-9.-]/g,”));
}
function compute(){
const sbp0 = parseNum(elBaselineSbp.value);
const risk0 = parseNum(elBaselineRisk.value);
// 유효성 검사
if(!isFinite(sbp0)){
alert(‘현재 수축기 혈압(SBP)을 입력해 주세요.’);
return;
}
if(sbp0260){
alert(‘SBP는 60~260 mmHg 범위에서 입력해 주세요.’);
return;
}
if(elMedContainer.children.length===0){
alert(‘약물을 1개 이상 추가해 주세요.’);
return;
}
const meds = collectMeds();
const totalDrop = meds.reduce((acc,m)=> acc + (POTENCY[m.class]||0)*(DOSE_MULT[m.dose]||1), 0);
const sbp1 = Math.max(80, sbp0 – totalDrop); // 과도한 저혈압 안전버퍼
const rr_reduction = Math.max(0, Math.min(1, (totalDrop * 0.02))); // 1 mmHg 당 2% 상대위험 감소 가정
const rows = [
`
`,
`
`,
`
`
];
if(isFinite(risk0)){
const absAfter = clamp01(risk0/100 * (1 – rr_reduction)) * 100;
rows.push(`
`);
}
let safetyMsgs = [];
if(sbp1/티아지드|MRA/.test(m.class))){ safetyMsgs.push(‘티아지드·MRA 사용 시 전해질(나트륨/칼륨)과 신기능 모니터링이 필요할 수 있습니다.’); }
if(meds.some(m=>/베타차단제/.test(m.class))){ safetyMsgs.push(‘베타차단제는 서맥·기관지 수축 등 금기 확인이 필요합니다.’); }
elResult.innerHTML = `
${rows.map(r=>`
${r}
`).join(”)}
약물 구성
- ${meds.map(m=>`
- ${m.class} · ${escapeHtml(m.note||’메모 없음’)} · ${m.dose}
`).join(”)}
${safetyMsgs.length?`
주의: ${safetyMsgs.join(‘ ‘)}
`:”}
`;
}
function liveCompute(){
// 입력이 변할 때 결과를 미리 갱신 (필수는 아님)
if(document.activeElement && [‘INPUT’,’SELECT’].includes(document.activeElement.tagName)) return;
if(!elBaselineSbp.value) return;
try{ compute(); }catch(e){/* noop */}
}
function collectMeds(){
const list = [];
[…elMedContainer.children].forEach(row=>{
const [selClass, inputNote, selDose] = row.querySelectorAll(‘select, input’);
list.push({ class: selClass.value, note: inputNote.value, dose: selDose.value });
});
return list;
}
function round1(x){ return Math.round(x*10)/10 }
function clamp01(x){ return Math.min(1, Math.max(0, x)) }
function copySummary(){
const txt = elResult.innerText.trim();
if(!txt){alert(‘복사할 결과가 없습니다. 먼저 계산해 주세요.’);return}
navigator.clipboard.writeText(txt).then(()=>{
toast(‘결과를 복사했습니다. 블로그 글에 붙여넣기 하세요.’);
}).catch(()=>alert(‘복사에 실패했습니다. 브라우저 설정을 확인해 주세요.’))
}
function toast(msg){
const t = document.createElement(‘div’);
t.textContent = msg;
t.style.position=’fixed’;t.style.bottom=’18px’;t.style.left=’50%’;t.style.transform=’translateX(-50%)’;
t.style.background=’#111827′;t.style.color=’#fff’;t.style.padding=’10px 14px’;t.style.borderRadius=’10px’;t.style.boxShadow=’0 6px 24px rgba(0,0,0,.18)’;
document.body.appendChild(t);
setTimeout(()=>t.remove(), 1800);
}
function escapeHtml(str){
return String(str).replace(/[&”‘]/g, s=>({“&”:”&”,””:”>”,”””:”"”,”‘”:”'”}[s]));
}
})();


Leave a Reply