diff --git a/backend/pmr_api.py b/backend/pmr_api.py index b97c738..d9158ab 100644 --- a/backend/pmr_api.py +++ b/backend/pmr_api.py @@ -518,3 +518,113 @@ def create_label_image(patient_name, med_name, add_info='', dosage=0, frequency= draw_centered("청 춘 약 국", pharmacy_y, info_font) return image + + +# ───────────────────────────────────────────────────────────── +# API: 환자 이전 처방 이력 +# ───────────────────────────────────────────────────────────── +@pmr_bp.route('/api/patient//history', methods=['GET']) +def get_patient_history(cus_code): + """ + 환자 이전 처방 이력 조회 + + Args: + cus_code: 환자 고유코드 (CusCode) + + Query Params: + - limit: 최대 조회 건수 (기본 10, 최대 50) + - exclude: 제외할 처방번호 (현재 처방) + """ + try: + limit = min(int(request.args.get('limit', 10)), 50) + exclude_serial = request.args.get('exclude', '') + + conn = get_mssql_connection('PM_PRES') + cursor = conn.cursor() + + # 이전 처방 목록 조회 + query = """ + SELECT TOP (?) + m.PreSerial, + m.PassDay, + m.PresTime, + m.Paname, + m.InsName, + m.Drname, + m.PRICE_P, + (SELECT COUNT(*) FROM PS_sub_pharm WHERE PreSerial = m.PreSerial) as drug_count + FROM PS_MAIN m + WHERE m.CusCode = ? + """ + params = [limit, cus_code] + + if exclude_serial: + query += " AND m.PreSerial != ?" + params.append(exclude_serial) + + query += " ORDER BY m.PassDay DESC, m.PresTime DESC" + + cursor.execute(query, params) + + history = [] + for row in cursor.fetchall(): + pre_serial = row.PreSerial + + # 해당 처방의 약품 목록 조회 + cursor.execute(""" + SELECT + s.DrugCode, + s.Days, + s.QUAN, + s.QUAN_TIME, + g.GoodsName, + m.PRINT_TYPE + FROM PS_sub_pharm s + LEFT JOIN PM_DRUG.dbo.CD_GOODS g ON s.DrugCode = g.DrugCode + LEFT JOIN PM_DRUG.dbo.CD_MC m ON s.DrugCode = m.DRUGCODE + WHERE s.PreSerial = ? + ORDER BY s.SUB_SERIAL + """, (pre_serial,)) + + medications = [] + for med_row in cursor.fetchall(): + medications.append({ + 'medication_code': med_row.DrugCode or '', + 'med_name': med_row.GoodsName or med_row.DrugCode or '', + 'add_info': med_row.PRINT_TYPE or '', + 'dosage': float(med_row.QUAN) if med_row.QUAN else 0, + 'frequency': med_row.QUAN_TIME or 0, + 'duration': med_row.Days or 0 + }) + + # 날짜 포맷 + pass_day = row.PassDay + if pass_day and len(pass_day) == 8: + date_formatted = f"{pass_day[:4]}-{pass_day[4:6]}-{pass_day[6:8]}" + else: + date_formatted = pass_day or '' + + history.append({ + 'prescription_id': pre_serial, + 'date': date_formatted, + 'time': row.PresTime or '', + 'patient_name': row.Paname or '', + 'hospital': row.InsName or '', + 'doctor': row.Drname or '', + 'copayment': int(row.PRICE_P or 0), + 'medication_count': row.drug_count or 0, + 'medications': medications + }) + + conn.close() + + return jsonify({ + 'success': True, + 'cus_code': cus_code, + 'count': len(history), + 'history': history + }) + + except Exception as e: + logging.error(f"환자 이전 처방 조회 오류: {e}") + return jsonify({'success': False, 'error': str(e)}), 500 diff --git a/backend/templates/pmr.html b/backend/templates/pmr.html index 8c39e33..a1c7be2 100644 --- a/backend/templates/pmr.html +++ b/backend/templates/pmr.html @@ -242,6 +242,75 @@ animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } + + /* 이전 처방 비교 영역 */ + .history-section { + border-top: 3px solid #e2e8f0; + background: #fafafa; + } + .history-header { + background: linear-gradient(135deg, #64748b, #94a3b8); + color: #fff; + padding: 12px 20px; + display: flex; + justify-content: space-between; + align-items: center; + } + .history-header .title { font-weight: 600; } + .history-nav { + display: flex; + align-items: center; + gap: 10px; + } + .history-nav button { + background: rgba(255,255,255,0.2); + border: none; + color: #fff; + width: 32px; + height: 32px; + border-radius: 50%; + font-size: 1.1rem; + cursor: pointer; + transition: all 0.2s; + } + .history-nav button:hover:not(:disabled) { background: rgba(255,255,255,0.4); } + .history-nav button:disabled { opacity: 0.4; cursor: not-allowed; } + .history-nav .index { font-size: 0.9rem; } + .history-info { + padding: 10px 20px; + background: #f1f5f9; + font-size: 0.85rem; + color: #64748b; + display: flex; + gap: 15px; + } + .history-meds { + max-height: 200px; + overflow-y: auto; + padding: 10px 20px; + } + .history-meds table { + width: 100%; + border-collapse: collapse; + font-size: 0.85rem; + } + .history-meds th { + background: #e2e8f0; + padding: 8px 10px; + text-align: left; + font-weight: 600; + color: #475569; + } + .history-meds td { + padding: 8px 10px; + border-bottom: 1px solid #e2e8f0; + } + .history-meds .med-name { font-weight: 500; } + .history-empty { + padding: 30px; + text-align: center; + color: #94a3b8; + } @@ -310,11 +379,30 @@ + + +