feat: 동물약 안내서 기능 추가

- 동물약 뱃지 클릭 시 약품 정보 모달 표시
- APC 코드로 PostgreSQL 조회 (효능효과, 용법용량, 주의사항)
- HTML 태그 파싱하여 텍스트 표시
- ESC/POS 인쇄 API 준비 (프린터 연결 시 활성화)
- 미리보기 API: /api/animal-drug-info/preview
- 인쇄 API: /api/animal-drug-info/print
This commit is contained in:
thug0bin
2026-03-04 19:18:10 +09:00
parent 77c667e1f6
commit 321fd0de1e
2 changed files with 361 additions and 1 deletions

View File

@@ -417,6 +417,24 @@
border-radius: 9px;
vertical-align: middle;
}
.animal-badge {
display: inline-block;
background: #10b981;
color: #fff;
font-size: 11px;
padding: 2px 6px;
border-radius: 4px;
margin-left: 6px;
}
.animal-badge.clickable {
cursor: pointer;
transition: all 0.2s;
}
.animal-badge.clickable:hover {
background: #059669;
box-shadow: 0 2px 8px rgba(16,185,129,0.4);
transform: scale(1.05);
}
.code-na {
background: #f1f5f9;
color: #94a3b8;
@@ -1061,7 +1079,7 @@
<td>
<div class="product-name">
${escapeHtml(item.product_name)}
${item.is_animal_drug ? '<span style="display:inline-block;background:#10b981;color:#fff;font-size:11px;padding:2px 6px;border-radius:4px;margin-left:6px;">🐾 동물약</span>' : ''}
${item.is_animal_drug ? `<span class="animal-badge ${item.apc ? 'clickable' : ''}" ${item.apc ? `onclick="printAnimalDrugInfo('${item.apc}', '${escapeHtml(item.product_name)}')" title="클릭하면 약품 안내서 인쇄"` : 'title="APC 없음"'}>🐾 동물약</span>` : ''}
${categoryBadge}
</div>
<div class="product-supplier ${item.is_set ? 'set' : ''}">${escapeHtml(item.supplier) || ''}</div>
@@ -1085,6 +1103,101 @@
`}).join('');
}
// ── 동물약 안내서 ──
async function printAnimalDrugInfo(apc, productName) {
if (!apc) {
alert('APC 코드가 없습니다.');
return;
}
// 미리보기 API 호출
try {
const res = await fetch('/api/animal-drug-info/preview', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ apc })
});
const data = await res.json();
if (data.success && data.data) {
showAnimalDrugModal(data.data, apc);
} else {
alert(`정보 조회 실패: ${data.error}`);
}
} catch (err) {
alert(`조회 오류: ${err.message}`);
}
}
function showAnimalDrugModal(info, apc) {
// 기존 모달이 있으면 제거
let modal = document.getElementById('animalDrugModal');
if (modal) modal.remove();
// 모달 생성
modal = document.createElement('div');
modal.id = 'animalDrugModal';
modal.className = 'modal-overlay';
modal.innerHTML = `
<div class="modal-content" style="max-width:500px;max-height:80vh;overflow-y:auto;">
<h3 style="margin:0 0 15px;color:#7c3aed;">🐾 동물약 안내서</h3>
<div style="background:#f8fafc;padding:15px;border-radius:8px;margin-bottom:15px;">
<h4 style="margin:0 0 8px;color:#1e293b;">${escapeHtml(info.product_name)}</h4>
<p style="margin:0;color:#64748b;font-size:13px;">제조: ${escapeHtml(info.company_name || '-')}</p>
${info.main_ingredient ? `<p style="margin:8px 0 0;color:#64748b;font-size:12px;">주성분: ${escapeHtml(info.main_ingredient)}</p>` : ''}
</div>
${info.efficacy_effect ? `
<div style="margin-bottom:12px;">
<h5 style="margin:0 0 6px;color:#059669;">▶ 효능효과</h5>
<p style="margin:0;font-size:13px;line-height:1.5;color:#334155;">${escapeHtml(info.efficacy_effect)}</p>
</div>` : ''}
${info.dosage_instructions ? `
<div style="margin-bottom:12px;">
<h5 style="margin:0 0 6px;color:#0284c7;">▶ 용법용량</h5>
<p style="margin:0;font-size:13px;line-height:1.5;color:#334155;">${escapeHtml(info.dosage_instructions)}</p>
</div>` : ''}
${info.precautions ? `
<div style="margin-bottom:12px;">
<h5 style="margin:0 0 6px;color:#dc2626;">▶ 주의사항</h5>
<p style="margin:0;font-size:13px;line-height:1.5;color:#334155;">${escapeHtml(info.precautions.substring(0, 500))}${info.precautions.length > 500 ? '...' : ''}</p>
</div>` : ''}
<div style="display:flex;gap:10px;margin-top:20px;">
<button onclick="document.getElementById('animalDrugModal').remove()"
style="flex:1;padding:10px;border:1px solid #e2e8f0;background:#fff;border-radius:6px;cursor:pointer;">닫기</button>
<button onclick="printAnimalDrugSheet('${apc}')"
style="flex:1;padding:10px;border:none;background:#7c3aed;color:#fff;border-radius:6px;cursor:pointer;">🖨️ 인쇄</button>
</div>
</div>
`;
modal.onclick = (e) => { if (e.target === modal) modal.remove(); };
document.body.appendChild(modal);
modal.classList.add('active');
}
async function printAnimalDrugSheet(apc) {
try {
const res = await fetch('/api/animal-drug-info/print', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ apc })
});
const data = await res.json();
if (data.success) {
alert('인쇄 완료!');
document.getElementById('animalDrugModal').remove();
} else {
alert(`인쇄 실패: ${data.error}`);
}
} catch (err) {
alert(`인쇄 오류: ${err.message}`);
}
}
// ── QR 인쇄 관련 ──
function adjustQty(delta) {
printQty = Math.max(MIN_QTY, Math.min(MAX_QTY, printQty + delta));