feat: 특이사항(CUSETC) 영수증 인쇄 기능 추가

- pos_printer.py: print_cusetc() 함수 추가 (ESC/POS 영수증 출력)
- admin.html: 회원 상세 모달에 🖨️ 인쇄 버튼 추가
- 즉시 피드백 토스트 + API 응답 후 결과 표시
This commit is contained in:
thug0bin
2026-03-04 12:10:00 +09:00
parent 5074adce20
commit 9ce7e884d7
2 changed files with 90 additions and 72 deletions

View File

@@ -20,6 +20,41 @@
-webkit-font-smoothing: antialiased;
}
/* 토스트 알림 */
.toast-container {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
display: flex;
flex-direction: column;
gap: 10px;
}
.toast {
padding: 14px 20px;
border-radius: 10px;
color: white;
font-weight: 500;
font-size: 14px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
animation: toastIn 0.3s ease, toastOut 0.3s ease 2.7s forwards;
display: flex;
align-items: center;
gap: 10px;
}
.toast.success { background: linear-gradient(135deg, #10b981 0%, #059669 100%); }
.toast.error { background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); }
.toast.info { background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); }
.toast.printing { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); }
@keyframes toastIn {
from { opacity: 0; transform: translateX(100px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes toastOut {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(100px); }
}
.header {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
padding: 32px 24px;
@@ -944,31 +979,53 @@
if (editBtn) editBtn.style.display = 'inline-block';
}
// 특이사항 인쇄
async function printCusetc(customerName, cusetc, phone) {
if (!confirm(`${customerName}님의 특이사항을 인쇄하시겠습니까?`)) {
return;
// 토스트 알림 함수
function showToast(message, type = 'info') {
let container = document.querySelector('.toast-container');
if (!container) {
container = document.createElement('div');
container.className = 'toast-container';
document.body.appendChild(container);
}
const toast = document.createElement('div');
toast.className = `toast ${type}`;
const icons = { success: '✅', error: '❌', info: '', printing: '🖨️' };
toast.innerHTML = `<span>${icons[type] || ''}</span><span>${message}</span>`;
container.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
// 인쇄용 전역 변수
let printData = { name: '', cusetc: '', phone: '' };
// 특이사항 인쇄 실행
async function doPrintCusetc() {
// 즉시 피드백
showToast(`${printData.name}님 특이사항 인쇄 중...`, 'printing');
try {
const res = await fetch('/api/print/cusetc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
customer_name: customerName,
cusetc: cusetc,
phone: phone
customer_name: printData.name,
cusetc: printData.cusetc,
phone: printData.phone
})
});
const data = await res.json();
if (data.success) {
alert('🖨️ ' + data.message);
showToast(data.message, 'success');
} else {
alert('인쇄 실패: ' + (data.error || '알 수 없는 오류'));
showToast('인쇄 실패: ' + (data.error || '알 수 없는 오류'), 'error');
}
} catch (err) {
alert('오류: ' + err.message);
showToast('오류: ' + err.message, 'error');
}
}
@@ -1015,7 +1072,7 @@
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 6px;">
<span style="color: #d97706; font-size: 13px;">⚠️ 특이사항</span>
<button onclick="editCusetc('${data.pos_customer.cuscode}', this)" style="background: none; border: 1px solid #d97706; color: #d97706; font-size: 11px; padding: 2px 8px; border-radius: 4px; cursor: pointer;">✏️ 수정</button>
${data.pos_customer.cusetc ? `<button onclick="printCusetc('${data.pos_customer.name}', '${(data.pos_customer.cusetc || '').replace(/'/g, "\\'")}', '${user.phone || ''}')" style="background: none; border: 1px solid #6b7280; color: #6b7280; font-size: 11px; padding: 2px 8px; border-radius: 4px; cursor: pointer;">🖨️ 인쇄</button>` : ''}
${data.pos_customer.cusetc ? `<button onclick="printData={name:'${data.pos_customer.name}',cusetc:decodeURIComponent('${encodeURIComponent(data.pos_customer.cusetc)}'),phone:'${user.phone||''}'};doPrintCusetc()" style="background: none; border: 1px solid #6b7280; color: #6b7280; font-size: 11px; padding: 2px 8px; border-radius: 4px; cursor: pointer;">🖨️ 인쇄</button>` : ''}
</div>
<div id="cusetc-view" onclick="toggleCusetc(this)" style="color: #92400e; font-size: 14px; font-weight: 500; cursor: ${(data.pos_customer.cusetc || '').length > 30 ? 'pointer' : 'default'}; ${(data.pos_customer.cusetc || '').length > 30 ? 'max-height: 40px; overflow: hidden;' : ''}" title="${(data.pos_customer.cusetc || '').length > 30 ? '클릭하여 펼치기' : ''}">
${data.pos_customer.cusetc || '<span style="color: #9ca3af; font-weight: normal;">없음</span>'}