feat: PMR 효능효과(add_info) 추가

- CD_MC.PRINT_TYPE JOIN으로 효능 조회
- 약품 테이블에 효능 표시
- 라벨 미리보기에 효능 포함
This commit is contained in:
thug0bin 2026-03-04 22:56:28 +09:00
parent c21aa956da
commit fc2db78816
2 changed files with 50 additions and 18 deletions

View File

@ -176,7 +176,7 @@ def get_prescription_detail(prescription_id):
conn.close()
return jsonify({'success': False, 'error': '처방전을 찾을 수 없습니다'}), 404
# 처방 약품 목록 (PS_sub_pharm + PM_DRUG.CD_GOODS JOIN)
# 처방 약품 목록 (PS_sub_pharm + CD_GOODS + CD_MC JOIN)
medications = []
cursor.execute("""
SELECT
@ -187,17 +187,24 @@ def get_prescription_detail(prescription_id):
s.PS_Type,
s.INV_QUAN,
g.GoodsName,
g.SUNG_CODE
g.SUNG_CODE,
m.PRINT_TYPE,
m.SIM_EFFECT
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
""", (prescription_id,))
for row in cursor.fetchall():
# 효능: PRINT_TYPE > SIM_EFFECT > 없음
add_info = row.PRINT_TYPE or row.SIM_EFFECT or ''
medications.append({
'medication_code': row.DrugCode or '',
'med_name': row.GoodsName or row.DrugCode or '',
'add_info': add_info,
'dosage': float(row.QUAN) if row.QUAN else 0,
'frequency': row.QUAN_TIME or 0,
'duration': row.Days or 0,
@ -346,6 +353,7 @@ def preview_label():
patient_name = data.get('patient_name', '')
med_name = data.get('med_name', '')
add_info = data.get('add_info', '')
dosage = float(data.get('dosage', 0))
frequency = int(data.get('frequency', 0))
duration = int(data.get('duration', 0))
@ -355,6 +363,7 @@ def preview_label():
image = create_label_image(
patient_name=patient_name,
med_name=med_name,
add_info=add_info,
dosage=dosage,
frequency=frequency,
duration=duration,
@ -377,7 +386,7 @@ def preview_label():
return jsonify({'success': False, 'error': str(e)}), 500
def create_label_image(patient_name, med_name, dosage, frequency, duration, unit=''):
def create_label_image(patient_name, med_name, add_info='', dosage=0, frequency=0, duration=0, unit=''):
"""
라벨 이미지 생성 (29mm 용지 기준)
"""
@ -442,19 +451,17 @@ def create_label_image(patient_name, med_name, dosage, frequency, duration, unit
# 괄호 앞에서 분리
if '(' in med_name:
main_name = med_name.split('(')[0].strip()
sub_info = '(' + med_name.split('(', 1)[1] if '(' in med_name else ''
else:
main_name = med_name
sub_info = ''
# 약품명 줄바꿈
name_lines = wrap_text(main_name, drug_font, label_width - 30)
for line in name_lines:
y = draw_centered(line, y, drug_font)
# 부가정보
if sub_info:
y = draw_centered(sub_info, y, small_font, fill="gray")
# 효능효과 (add_info)
if add_info:
y = draw_centered(f"({add_info})", y, small_font, fill="gray")
y += 5

View File

@ -316,6 +316,14 @@
<script>
let currentPrescriptionId = null;
// HTML 이스케이프
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 초기화
document.addEventListener('DOMContentLoaded', () => {
const today = new Date().toISOString().split('T')[0];
@ -429,11 +437,12 @@
</thead>
<tbody>
${data.medications.map(m => `
<tr>
<tr data-add-info="${escapeHtml(m.add_info || '')}">
<td><input type="checkbox" class="med-check" data-code="${m.medication_code}" ${m.is_auto_print ? 'checked' : ''}></td>
<td>
<div class="med-name">${m.med_name || m.medication_code}</div>
<div class="med-code">${m.medication_code}</div>
${m.add_info ? `<div style="font-size:0.75rem;color:#6b7280;">${escapeHtml(m.add_info)}</div>` : ''}
</td>
<td>${m.formulation ? `<span class="med-form">${m.formulation}</span>` : '-'}</td>
<td><span class="med-dosage">${m.dosage || '-'}</span></td>
@ -481,8 +490,8 @@
// 라벨 미리보기
async function previewLabels() {
const rows = document.querySelectorAll('.med-check:checked');
if (rows.length === 0) {
const checkboxes = document.querySelectorAll('.med-check:checked');
if (checkboxes.length === 0) {
alert('미리보기할 약품을 선택하세요');
return;
}
@ -496,12 +505,24 @@
container.innerHTML = '';
for (const checkbox of rows) {
for (const checkbox of checkboxes) {
const tr = checkbox.closest('tr');
const medName = tr.querySelector('.med-name')?.textContent || '';
const dosage = parseFloat(tr.cells[3]?.querySelector('.med-dosage')?.textContent) || 0;
const frequency = parseInt(tr.cells[4]?.textContent) || 0;
const duration = parseInt(tr.cells[5]?.textContent) || 0;
const cells = tr.querySelectorAll('td');
// 약품명: 두 번째 셀의 .med-name
const medName = tr.querySelector('.med-name')?.textContent?.trim() || '';
const addInfo = tr.dataset.addInfo || '';
// 용량: 네 번째 셀 (index 3)
const dosageText = cells[3]?.textContent?.replace(/[^0-9.]/g, '') || '0';
const dosage = parseFloat(dosageText) || 0;
// 횟수: 다섯 번째 셀 (index 4)
const freqText = cells[4]?.textContent?.replace(/[^0-9]/g, '') || '0';
const frequency = parseInt(freqText) || 0;
// 일수: 여섯 번째 셀 (index 5)
const durText = cells[5]?.textContent?.replace(/[^0-9]/g, '') || '0';
const duration = parseInt(durText) || 0;
console.log('Preview data:', { patientName, medName, addInfo, dosage, frequency, duration });
try {
const res = await fetch('/pmr/api/label/preview', {
@ -510,6 +531,7 @@
body: JSON.stringify({
patient_name: patientName,
med_name: medName,
add_info: addInfo,
dosage: dosage,
frequency: frequency,
duration: duration,
@ -517,12 +539,15 @@
})
});
const data = await res.json();
console.log('Preview response:', data.success, data.error);
if (data.success) {
if (data.success && data.image) {
const img = document.createElement('img');
img.src = data.image;
img.style.cssText = 'max-width:100%;border:1px solid #ddd;border-radius:8px;';
container.appendChild(img);
} else {
console.error('Preview failed:', data.error);
}
} catch (err) {
console.error('Preview error:', err);
@ -530,7 +555,7 @@
}
if (container.children.length === 0) {
container.innerHTML = '<p style="color:#999;">미리보기 생성 실패</p>';
container.innerHTML = '<p style="color:#999;">미리보기 생성 실패 - 콘솔(F12) 확인</p>';
}
}