fix: 자동인쇄 중복 방지 + 인쇄 로깅 추가

문제: 같은 처방이 2번 인쇄됨
원인: printPaaiResult가 2곳에서 호출 (API 응답 + WebSocket 이벤트)

해결:
- window.printedSerials (Set) 으로 중복 인쇄 방지
- 인쇄 성공 시 Set에 추가
- 5분 후 자동 제거 (메모리 관리)

로깅 추가:
- 프론트: 콘솔에 시간 + 환자명 + 상태
- 백엔드: logs/print_history.log 파일에 기록
This commit is contained in:
thug0bin 2026-03-05 12:56:39 +09:00
parent 2eb92daf3e
commit c7169e6679
2 changed files with 52 additions and 9 deletions

View File

@ -1461,6 +1461,23 @@ _INIT = _ESC + b'@' # 프린터 초기화
_CUT = _ESC + b'd\x03' # 피드 + 커트
def _log_print_history(pre_serial, patient_name, success, error=None):
"""인쇄 이력을 파일에 기록"""
try:
log_dir = Path(__file__).parent / 'logs'
log_dir.mkdir(exist_ok=True)
log_file = log_dir / 'print_history.log'
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
status = '✅ 성공' if success else f'❌ 실패: {error}'
line = f"[{timestamp}] {pre_serial} | {patient_name} | {status}\n"
with open(log_file, 'a', encoding='utf-8') as f:
f.write(line)
except Exception as e:
logging.warning(f"인쇄 로그 기록 실패: {e}")
@pmr_bp.route('/api/paai/print', methods=['POST'])
def paai_print():
"""PAAI 분석 결과 ESC/POS 인쇄"""
@ -1473,6 +1490,8 @@ def paai_print():
analysis = result.get('analysis', {})
kims_summary = result.get('kims_summary', {})
logging.info(f"[PRINT] 요청 수신: {pre_serial} ({patient_name})")
# 영수증 텍스트 생성
message = _format_paai_receipt(pre_serial, patient_name, analysis, kims_summary)
@ -1480,13 +1499,17 @@ def paai_print():
success = _print_escpos_text(message)
if success:
logging.info(f"PAAI 인쇄 완료: {pre_serial} ({patient_name})")
logging.info(f"[PRINT] ✅ 완료: {pre_serial} ({patient_name})")
_log_print_history(pre_serial, patient_name, True)
return jsonify({'success': True, 'message': '인쇄 완료'})
else:
logging.error(f"[PRINT] ❌ 프린터 연결 실패: {pre_serial}")
_log_print_history(pre_serial, patient_name, False, '프린터 연결 실패')
return jsonify({'success': False, 'error': '프린터 연결 실패'}), 500
except Exception as e:
logging.error(f"PAAI 인쇄 오류: {e}")
logging.error(f"[PRINT] ❌ 오류: {pre_serial} - {e}")
_log_print_history(pre_serial, patient_name, False, str(e))
return jsonify({'success': False, 'error': str(e)}), 500

View File

@ -2650,6 +2650,7 @@
// 자동인쇄 기능 (모두 window 전역)
// ═══════════════════════════════════════════════════════════════
window.autoPrintEnabled = localStorage.getItem('pmr_auto_print') === 'true';
window.printedSerials = new Set(); // 중복 인쇄 방지용
// 간단한 토스트 알림
window.showToast = function(message, type) {
@ -2678,15 +2679,25 @@
}
};
// PAAI 결과 인쇄
// PAAI 결과 인쇄 (중복 방지 포함)
window.printPaaiResult = async function(preSerial, patientName, result) {
// 1. 자동인쇄 비활성화 체크
if (!window.autoPrintEnabled) {
console.log('[AutoPrint] 비활성화됨');
console.log('[AutoPrint] 비활성화됨, 스킵:', preSerial);
return;
}
// 2. 중복 인쇄 방지
if (window.printedSerials.has(preSerial)) {
console.log('[AutoPrint] 이미 인쇄됨, 스킵:', preSerial);
return;
}
// 3. 인쇄 진행
try {
console.log('[AutoPrint] 인쇄 요청:', preSerial);
var now = new Date().toLocaleTimeString('ko-KR');
console.log('[AutoPrint] ' + now + ' 인쇄 요청:', preSerial, patientName);
var response = await fetch('/pmr/api/paai/print', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
@ -2699,13 +2710,22 @@
var data = await response.json();
if (data.success) {
console.log('[AutoPrint] 인쇄 완료');
window.showToast('인쇄 완료: ' + patientName, 'success');
// 인쇄 성공 → Set에 추가 (중복 방지)
window.printedSerials.add(preSerial);
console.log('[AutoPrint] ' + now + ' ✅ 인쇄 완료:', preSerial, patientName);
window.showToast('🖨️ ' + patientName, 'success');
// 5분 후 Set에서 제거 (메모리 관리)
setTimeout(function() {
window.printedSerials.delete(preSerial);
}, 5 * 60 * 1000);
} else {
console.error('[AutoPrint] 실패:', data.error);
console.error('[AutoPrint] ' + now + ' ❌ 실패:', preSerial, data.error);
window.showToast('인쇄 실패: ' + patientName, 'error');
}
} catch (err) {
console.error('[AutoPrint] 오류:', err);
console.error('[AutoPrint] 오류:', preSerial, err);
window.showToast('인쇄 오류', 'error');
}
};