feat: 실시간 POS 품목별 OTC 용법 라벨 인쇄 버튼 추가
POS 상세 패널:
- 품목 목록에 💊 인쇄 버튼 추가
- 프리셋 있으면 → 바로 인쇄
- 프리셋 없으면 → 새 창으로 등록 페이지 열기
API:
- /api/admin/pos-live/detail에 barcode 필드 추가
OTC 라벨 관리 페이지:
- URL 파라미터(barcode, name) 자동 처리
- POS에서 넘어올 때 자동으로 해당 약품 로드
This commit is contained in:
@@ -401,6 +401,30 @@
|
||||
debounceTimer = setTimeout(previewLabel, 500);
|
||||
});
|
||||
});
|
||||
|
||||
// URL 파라미터로 바코드/이름 전달 시 자동 로드
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const urlBarcode = params.get('barcode');
|
||||
const urlName = params.get('name');
|
||||
if (urlBarcode) {
|
||||
currentBarcode = urlBarcode;
|
||||
currentDrugName = urlName || urlBarcode;
|
||||
document.getElementById('barcode').value = urlBarcode;
|
||||
document.getElementById('searchInput').value = urlName || urlBarcode;
|
||||
|
||||
// 기존 프리셋 확인
|
||||
fetch(`/api/admin/otc-labels/${urlBarcode}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.exists) {
|
||||
document.getElementById('displayName').value = data.label.display_name || '';
|
||||
document.getElementById('effect').value = data.label.effect || '';
|
||||
document.getElementById('dosageInstruction').value = data.label.dosage_instruction || '';
|
||||
document.getElementById('usageTip').value = data.label.usage_tip || '';
|
||||
}
|
||||
previewLabel();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 약품 검색 (MSSQL)
|
||||
|
||||
@@ -400,6 +400,24 @@
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
.item-label-btn {
|
||||
padding: 4px 8px;
|
||||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.item-label-btn:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 2px 8px rgba(245,158,11,0.4);
|
||||
}
|
||||
.item-label-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
/* ── 오버레이 ── */
|
||||
.overlay {
|
||||
@@ -1139,6 +1157,7 @@
|
||||
<span class="detail-item-name">${item.product_name}</span>
|
||||
<span class="detail-item-qty">×${item.quantity}</span>
|
||||
<span class="detail-item-price">₩${Math.floor(item.total_price).toLocaleString()}</span>
|
||||
${item.barcode ? `<button class="item-label-btn" onclick="printOtcLabel('${item.barcode}', '${escapeHtml(item.product_name)}')">💊</button>` : ''}
|
||||
</div>
|
||||
`).join('');
|
||||
document.getElementById('itemsList').innerHTML = itemsHtml;
|
||||
@@ -1149,6 +1168,61 @@
|
||||
document.getElementById('itemsList').innerHTML = `<div class="empty-state">오류: ${err.message}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
// OTC 용법 라벨 인쇄
|
||||
async function printOtcLabel(barcode, productName) {
|
||||
const btn = event.target;
|
||||
btn.disabled = true;
|
||||
btn.textContent = '...';
|
||||
|
||||
try {
|
||||
// 프리셋 확인
|
||||
const checkRes = await fetch(`/api/admin/otc-labels/${barcode}`);
|
||||
const checkData = await checkRes.json();
|
||||
|
||||
if (checkData.exists) {
|
||||
// 프리셋 있음 → 바로 인쇄
|
||||
const preset = checkData.label;
|
||||
const printRes = await fetch('/api/admin/otc-labels/print', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
barcode: barcode,
|
||||
drug_name: preset.display_name || productName,
|
||||
effect: preset.effect || '',
|
||||
dosage_instruction: preset.dosage_instruction || '',
|
||||
usage_tip: preset.usage_tip || ''
|
||||
})
|
||||
});
|
||||
const printData = await printRes.json();
|
||||
|
||||
if (printData.success) {
|
||||
btn.textContent = '✓';
|
||||
btn.style.background = '#10b981';
|
||||
showToast(`용법 라벨 인쇄 완료!`, 'success');
|
||||
} else {
|
||||
btn.textContent = '💊';
|
||||
btn.disabled = false;
|
||||
showToast(printData.error || '인쇄 실패', 'error');
|
||||
}
|
||||
} else {
|
||||
// 프리셋 없음 → 새 창으로 등록 페이지 열기
|
||||
btn.textContent = '💊';
|
||||
btn.disabled = false;
|
||||
showToast('프리셋 미등록 → 등록 페이지로 이동', 'info');
|
||||
window.open(`/admin/otc-labels?barcode=${barcode}&name=${encodeURIComponent(productName)}`, '_blank', 'width=1200,height=800');
|
||||
}
|
||||
} catch (err) {
|
||||
btn.textContent = '💊';
|
||||
btn.disabled = false;
|
||||
showToast('오류: ' + err.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
if (!str) return '';
|
||||
return str.replace(/[&<>"']/g, m => ({'&':'&','<':'<','>':'>','"':'"',"'":'''})[m]);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 상세 패널에서 단일 건 처리
|
||||
|
||||
Reference in New Issue
Block a user