feat(admin): 제품 사용이력 + 환자 최근처방 모달 기능
- GET /api/products/<drug_code>/usage-history - 제품별 처방 이력 조회 (환자명, 수량, 횟수, 일수, 총투약량) - 페이지네이션 + 기간 필터 지원 - GET /api/patients/<cus_code>/recent-prescriptions - 환자 최근 6개월 처방 내역 - 약품별 분류(CD_MC.PRINT_TYPE) 표시 (당뇨치료, 고지혈치료 등) - admin_products.html 모달 2개 추가 - 제품명 클릭 → 사용이력 모달 (횟수 포함 정확한 총투약량) - 환자명 클릭 → 최근처방 모달 (z-index 2100으로 위에 표시) DB 조인: - PS_main.PreSerial = PS_sub_pharm.PreSerial - CD_GOODS + CD_MC (PRINT_TYPE 분류)
This commit is contained in:
parent
83ecf88bd4
commit
688bdb40f2
232
backend/app.py
232
backend/app.py
@ -3872,6 +3872,238 @@ def api_drug_purchase_history(drug_code):
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
# ==================== 처방 사용이력 API ====================
|
||||
|
||||
@app.route('/api/products/<drug_code>/usage-history')
|
||||
def api_product_usage_history(drug_code):
|
||||
"""
|
||||
제품 처방 사용이력 조회 API
|
||||
- PS_main + PS_sub_pharm JOIN
|
||||
- 페이지네이션, 기간 필터 지원
|
||||
- 환자명 마스킹 처리
|
||||
"""
|
||||
page = int(request.args.get('page', 1))
|
||||
per_page = int(request.args.get('per_page', 20))
|
||||
months = int(request.args.get('months', 12))
|
||||
|
||||
offset = (page - 1) * per_page
|
||||
|
||||
try:
|
||||
pres_session = db_manager.get_session('PM_PRES')
|
||||
|
||||
# 기간 계산 (N개월 전부터)
|
||||
from datetime import datetime, timedelta
|
||||
start_date = (datetime.now() - timedelta(days=months * 30)).strftime('%Y%m%d')
|
||||
|
||||
# 총 건수 조회 (COUNT)
|
||||
count_result = pres_session.execute(text("""
|
||||
SELECT COUNT(*) as total_count
|
||||
FROM PS_sub_pharm sp
|
||||
JOIN PS_main pm ON pm.PreSerial = sp.PreSerial
|
||||
WHERE sp.DrugCode = :drug_code
|
||||
AND pm.Indate >= :start_date
|
||||
AND (sp.PS_Type IS NULL OR sp.PS_Type != '9')
|
||||
"""), {'drug_code': drug_code, 'start_date': start_date})
|
||||
total_count = count_result.fetchone()[0]
|
||||
|
||||
# 데이터 조회 (페이지네이션)
|
||||
data_result = pres_session.execute(text("""
|
||||
SELECT
|
||||
pm.Paname as patient_name,
|
||||
pm.CusCode as cus_code,
|
||||
pm.Indate as rx_date,
|
||||
sp.QUAN as quantity,
|
||||
sp.QUAN_TIME as times,
|
||||
sp.Days as days
|
||||
FROM PS_sub_pharm sp
|
||||
JOIN PS_main pm ON pm.PreSerial = sp.PreSerial
|
||||
WHERE sp.DrugCode = :drug_code
|
||||
AND pm.Indate >= :start_date
|
||||
AND (sp.PS_Type IS NULL OR sp.PS_Type != '9')
|
||||
ORDER BY pm.Indate DESC
|
||||
OFFSET :offset ROWS
|
||||
FETCH NEXT :per_page ROWS ONLY
|
||||
"""), {
|
||||
'drug_code': drug_code,
|
||||
'start_date': start_date,
|
||||
'offset': offset,
|
||||
'per_page': per_page
|
||||
})
|
||||
|
||||
items = []
|
||||
for row in data_result.fetchall():
|
||||
patient_name = row.patient_name or ''
|
||||
cus_code = row.cus_code or ''
|
||||
|
||||
# 날짜 포맷팅 (YYYYMMDD -> YYYY-MM-DD)
|
||||
rx_date = row.rx_date or ''
|
||||
if len(rx_date) == 8:
|
||||
rx_date = f"{rx_date[:4]}-{rx_date[4:6]}-{rx_date[6:8]}"
|
||||
|
||||
quantity = int(row.quantity) if row.quantity else 1
|
||||
times = int(row.times) if row.times else 1 # 횟수 (QUAN_TIME)
|
||||
days = int(row.days) if row.days else 1
|
||||
total_dose = quantity * times * days # 수량 × 횟수 × 일수
|
||||
|
||||
items.append({
|
||||
'patient_name': patient_name,
|
||||
'cus_code': cus_code,
|
||||
'rx_date': rx_date,
|
||||
'quantity': quantity,
|
||||
'times': times,
|
||||
'days': days,
|
||||
'total_dose': total_dose
|
||||
})
|
||||
|
||||
# 약품명 조회
|
||||
drug_session = db_manager.get_session('PM_DRUG')
|
||||
name_result = drug_session.execute(text("""
|
||||
SELECT GoodsName FROM CD_GOODS WHERE DrugCode = :drug_code
|
||||
"""), {'drug_code': drug_code})
|
||||
name_row = name_result.fetchone()
|
||||
product_name = name_row[0] if name_row else drug_code
|
||||
|
||||
# 총 페이지 수 계산
|
||||
total_pages = (total_count + per_page - 1) // per_page
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'product_name': product_name,
|
||||
'pagination': {
|
||||
'page': page,
|
||||
'per_page': per_page,
|
||||
'total_count': total_count,
|
||||
'total_pages': total_pages
|
||||
},
|
||||
'items': items
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"사용이력 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/patients/<cus_code>/recent-prescriptions')
|
||||
def api_patient_recent_prescriptions(cus_code):
|
||||
"""
|
||||
환자 최근 처방 내역 조회 API
|
||||
- 해당 환자가 최근에 어떤 약을 처방받았는지 확인
|
||||
- DB 부담 최소화: 최근 6개월, 최대 30건
|
||||
"""
|
||||
try:
|
||||
pres_session = db_manager.get_session('PM_PRES')
|
||||
drug_session = db_manager.get_session('PM_DRUG')
|
||||
|
||||
# 최근 6개월
|
||||
from datetime import datetime, timedelta
|
||||
start_date = (datetime.now() - timedelta(days=180)).strftime('%Y%m%d')
|
||||
|
||||
# 환자의 최근 처방전 조회 (최대 10건)
|
||||
rx_result = pres_session.execute(text("""
|
||||
SELECT TOP 10
|
||||
pm.PreSerial,
|
||||
pm.Paname as patient_name,
|
||||
pm.Indate as rx_date,
|
||||
pm.Drname as doctor_name,
|
||||
pm.OrderName as hospital_name
|
||||
FROM PS_main pm
|
||||
WHERE pm.CusCode = :cus_code
|
||||
AND pm.Indate >= :start_date
|
||||
ORDER BY pm.Indate DESC
|
||||
"""), {'cus_code': cus_code, 'start_date': start_date})
|
||||
|
||||
prescriptions = []
|
||||
for rx in rx_result.fetchall():
|
||||
# 날짜 포맷팅
|
||||
rx_date = rx.rx_date or ''
|
||||
if len(rx_date) == 8:
|
||||
rx_date = f"{rx_date[:4]}-{rx_date[4:6]}-{rx_date[6:8]}"
|
||||
|
||||
# 해당 처방의 약품 목록 조회
|
||||
items_result = pres_session.execute(text("""
|
||||
SELECT
|
||||
sp.DrugCode,
|
||||
sp.QUAN as quantity,
|
||||
sp.QUAN_TIME as times,
|
||||
sp.Days as days
|
||||
FROM PS_sub_pharm sp
|
||||
WHERE sp.PreSerial = :pre_serial
|
||||
AND (sp.PS_Type IS NULL OR sp.PS_Type != '9')
|
||||
"""), {'pre_serial': rx.PreSerial})
|
||||
|
||||
# 먼저 모든 약품 데이터를 리스트로 가져오기
|
||||
raw_items = items_result.fetchall()
|
||||
drug_codes = [item.DrugCode for item in raw_items]
|
||||
|
||||
# 약품명 + 성분명 + 분류(PRINT_TYPE) 일괄 조회
|
||||
drug_info_map = {}
|
||||
if drug_codes:
|
||||
placeholders = ','.join([f"'{dc}'" for dc in drug_codes])
|
||||
name_result = drug_session.execute(text(f"""
|
||||
SELECT g.DrugCode, g.GoodsName, s.SUNG_HNM, m.PRINT_TYPE
|
||||
FROM CD_GOODS g
|
||||
LEFT JOIN CD_SUNG s ON g.SUNG_CODE = s.SUNG_CODE
|
||||
LEFT JOIN CD_MC m ON g.DrugCode = m.DRUGCODE
|
||||
WHERE g.DrugCode IN ({placeholders})
|
||||
"""))
|
||||
for row in name_result.fetchall():
|
||||
drug_info_map[row[0]] = {
|
||||
'name': row[1],
|
||||
'ingredient': row[2] or '',
|
||||
'category': row[3] or '' # 분류 (알러지질환약 등)
|
||||
}
|
||||
|
||||
items = []
|
||||
for item in raw_items:
|
||||
info = drug_info_map.get(item.DrugCode, {})
|
||||
drug_name = info.get('name', item.DrugCode)
|
||||
ingredient = info.get('ingredient', '')
|
||||
category = info.get('category', '') # 분류 (알러지질환약 등)
|
||||
|
||||
quantity = int(item.quantity) if item.quantity else 1
|
||||
times = int(item.times) if item.times else 1
|
||||
days = int(item.days) if item.days else 1
|
||||
|
||||
items.append({
|
||||
'drug_code': item.DrugCode,
|
||||
'drug_name': drug_name,
|
||||
'category': category, # 분류 추가
|
||||
'quantity': quantity,
|
||||
'times': times,
|
||||
'days': days,
|
||||
'total_dose': quantity * times * days
|
||||
})
|
||||
|
||||
prescriptions.append({
|
||||
'pre_serial': rx.PreSerial,
|
||||
'rx_date': rx_date,
|
||||
'doctor_name': rx.doctor_name or '',
|
||||
'hospital_name': rx.hospital_name or '',
|
||||
'items': items
|
||||
})
|
||||
|
||||
# 환자명
|
||||
patient_name = prescriptions[0]['items'][0]['drug_name'] if prescriptions else ''
|
||||
if prescriptions and pres_session.execute(text("""
|
||||
SELECT TOP 1 Paname FROM PS_main WHERE CusCode = :cus_code
|
||||
"""), {'cus_code': cus_code}).fetchone():
|
||||
patient_name = pres_session.execute(text("""
|
||||
SELECT TOP 1 Paname FROM PS_main WHERE CusCode = :cus_code
|
||||
"""), {'cus_code': cus_code}).fetchone()[0]
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'cus_code': cus_code,
|
||||
'patient_name': patient_name,
|
||||
'prescription_count': len(prescriptions),
|
||||
'prescriptions': prescriptions
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"환자 처방 조회 오류: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
# ==================== 위치 정보 API ====================
|
||||
|
||||
@app.route('/api/locations')
|
||||
|
||||
@ -712,6 +712,57 @@
|
||||
.purchase-modal-btn:hover {
|
||||
background: #e2e8f0;
|
||||
}
|
||||
|
||||
/* ── 제품명 링크 스타일 ── */
|
||||
.product-name-link {
|
||||
cursor: pointer;
|
||||
transition: color 0.15s;
|
||||
}
|
||||
.product-name-link:hover {
|
||||
color: #8b5cf6;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ── 환자명 링크 스타일 ── */
|
||||
.patient-name-link {
|
||||
cursor: pointer;
|
||||
color: #1e293b;
|
||||
transition: all 0.15s;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.patient-name-link:hover {
|
||||
color: #8b5cf6;
|
||||
background: #f3e8ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ── 페이지네이션 버튼 ── */
|
||||
.pagination-btn {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
color: #475569;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.pagination-btn:hover:not(:disabled) {
|
||||
background: #f1f5f9;
|
||||
border-color: #cbd5e1;
|
||||
}
|
||||
.pagination-btn.active {
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
border-color: #10b981;
|
||||
}
|
||||
.pagination-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -1151,6 +1202,53 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 사용이력 모달 -->
|
||||
<!-- 환자 최근 처방 모달 (z-index 더 높게 - 제품 모달 위에 표시) -->
|
||||
<div class="purchase-modal" id="patientPrescriptionsModal" style="z-index: 2100;" onclick="if(event.target===this)closePatientPrescriptionsModal()">
|
||||
<div class="purchase-modal-content" style="max-width: 850px;">
|
||||
<div class="purchase-modal-header" style="background: linear-gradient(135deg, #8b5cf6, #7c3aed);">
|
||||
<h3>📋 환자 최근 처방</h3>
|
||||
<div class="drug-name" id="patientPrescriptionsName">-</div>
|
||||
</div>
|
||||
<div class="purchase-modal-body" id="patientPrescriptionsBody" style="max-height: 500px; overflow-y: auto;">
|
||||
<div class="purchase-empty"><div class="icon">📭</div><p>로딩 중...</p></div>
|
||||
</div>
|
||||
<div class="purchase-modal-footer">
|
||||
<button class="purchase-modal-btn" onclick="closePatientPrescriptionsModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="purchase-modal" id="usageHistoryModal" onclick="if(event.target===this)closeUsageHistoryModal()">
|
||||
<div class="purchase-modal-content" style="max-width: 700px;">
|
||||
<div class="purchase-modal-header" style="background: linear-gradient(135deg, #10b981, #059669);">
|
||||
<h3>💊 처방 사용이력</h3>
|
||||
<div class="drug-name" id="usageHistoryDrugName">-</div>
|
||||
</div>
|
||||
<div class="purchase-modal-body">
|
||||
<table class="purchase-history-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>환자명</th>
|
||||
<th>처방일</th>
|
||||
<th>수량</th>
|
||||
<th>횟수</th>
|
||||
<th>일수</th>
|
||||
<th>총투약량</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="usageHistoryBody">
|
||||
<tr><td colspan="6" class="purchase-empty"><div class="icon">📭</div><p>로딩 중...</p></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="purchase-modal-footer" style="flex-direction: column; gap: 12px;">
|
||||
<div id="usageHistoryPagination" style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: center;"></div>
|
||||
<button class="purchase-modal-btn" onclick="closeUsageHistoryModal()">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let productsData = [];
|
||||
let selectedItem = null;
|
||||
@ -1236,7 +1334,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="product-name">
|
||||
${escapeHtml(item.product_name)}
|
||||
<span class="product-name-link" onclick="event.stopPropagation();openUsageHistoryModal('${item.drug_code}', '${escapeHtml(item.product_name).replace(/'/g, "\\'")}')" title="클릭하여 사용이력 보기">${escapeHtml(item.product_name)}</span>
|
||||
${item.is_animal_drug ? `<span class="animal-badge ${item.apc ? 'clickable' : ''}" ${item.apc ? `onclick="event.stopPropagation();printAnimalDrugInfo('${item.apc}', '${escapeHtml(item.product_name)}')" title="클릭하면 약품 안내서 인쇄"` : 'title="APC 없음"'}>🐾 동물약</span>` : ''}
|
||||
${categoryBadge}
|
||||
</div>
|
||||
@ -2155,6 +2253,177 @@
|
||||
function closePurchaseModal() {
|
||||
document.getElementById('purchaseModal').classList.remove('show');
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════
|
||||
// 사용이력 모달
|
||||
// ══════════════════════════════════════════════════════════════════
|
||||
let currentUsageDrugCode = '';
|
||||
let currentUsageDrugName = '';
|
||||
let currentUsagePage = 1;
|
||||
|
||||
async function openUsageHistoryModal(drugCode, drugName) {
|
||||
currentUsageDrugCode = drugCode;
|
||||
currentUsageDrugName = drugName;
|
||||
currentUsagePage = 1;
|
||||
|
||||
const modal = document.getElementById('usageHistoryModal');
|
||||
const nameEl = document.getElementById('usageHistoryDrugName');
|
||||
|
||||
nameEl.textContent = drugName || drugCode;
|
||||
modal.classList.add('show');
|
||||
|
||||
await loadUsageHistoryPage(1);
|
||||
}
|
||||
|
||||
async function loadUsageHistoryPage(page) {
|
||||
currentUsagePage = page;
|
||||
const tbody = document.getElementById('usageHistoryBody');
|
||||
const pagination = document.getElementById('usageHistoryPagination');
|
||||
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="purchase-empty"><div class="icon">⏳</div><p>사용이력 조회 중...</p></td></tr>';
|
||||
pagination.innerHTML = '';
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/products/${currentUsageDrugCode}/usage-history?page=${page}&per_page=20&months=12`);
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
if (data.items.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="6" class="purchase-empty"><div class="icon">📭</div><p>최근 12개월간 사용이력이 없습니다</p></td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = data.items.map(item => `
|
||||
<tr>
|
||||
<td>
|
||||
<span class="patient-name-link" onclick="event.stopPropagation();openPatientPrescriptionsModal('${item.cus_code}', '${escapeHtml(item.patient_name).replace(/'/g, "\\'")}')" title="클릭하여 최근 처방 보기">${escapeHtml(item.patient_name)}</span>
|
||||
</td>
|
||||
<td class="purchase-date">${item.rx_date}</td>
|
||||
<td style="text-align: center;">${item.quantity}</td>
|
||||
<td style="text-align: center;">${item.times}</td>
|
||||
<td style="text-align: center;">${item.days}</td>
|
||||
<td style="text-align: center; font-weight: 600; color: #10b981;">${item.total_dose}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// 페이지네이션 렌더링
|
||||
renderUsageHistoryPagination(data.pagination);
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="6" class="purchase-empty"><div class="icon">⚠️</div><p>조회 실패: ${data.error}</p></td></tr>`;
|
||||
}
|
||||
} catch (err) {
|
||||
tbody.innerHTML = `<tr><td colspan="6" class="purchase-empty"><div class="icon">❌</div><p>오류: ${err.message}</p></td></tr>`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderUsageHistoryPagination(pg) {
|
||||
const pagination = document.getElementById('usageHistoryPagination');
|
||||
if (pg.total_pages <= 1) {
|
||||
pagination.innerHTML = `<span style="color: #64748b; font-size: 13px;">총 ${pg.total_count}건</span>`;
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
|
||||
// 이전 버튼
|
||||
html += `<button class="pagination-btn" ${pg.page <= 1 ? 'disabled' : ''} onclick="loadUsageHistoryPage(${pg.page - 1})">◀ 이전</button>`;
|
||||
|
||||
// 페이지 번호들
|
||||
const maxPages = 5;
|
||||
let startPage = Math.max(1, pg.page - Math.floor(maxPages / 2));
|
||||
let endPage = Math.min(pg.total_pages, startPage + maxPages - 1);
|
||||
if (endPage - startPage < maxPages - 1) {
|
||||
startPage = Math.max(1, endPage - maxPages + 1);
|
||||
}
|
||||
|
||||
if (startPage > 1) {
|
||||
html += `<button class="pagination-btn" onclick="loadUsageHistoryPage(1)">1</button>`;
|
||||
if (startPage > 2) html += `<span style="color: #94a3b8;">...</span>`;
|
||||
}
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
html += `<button class="pagination-btn ${i === pg.page ? 'active' : ''}" onclick="loadUsageHistoryPage(${i})">${i}</button>`;
|
||||
}
|
||||
|
||||
if (endPage < pg.total_pages) {
|
||||
if (endPage < pg.total_pages - 1) html += `<span style="color: #94a3b8;">...</span>`;
|
||||
html += `<button class="pagination-btn" onclick="loadUsageHistoryPage(${pg.total_pages})">${pg.total_pages}</button>`;
|
||||
}
|
||||
|
||||
// 다음 버튼
|
||||
html += `<button class="pagination-btn" ${pg.page >= pg.total_pages ? 'disabled' : ''} onclick="loadUsageHistoryPage(${pg.page + 1})">다음 ▶</button>`;
|
||||
|
||||
// 총 건수
|
||||
html += `<span style="color: #64748b; font-size: 13px; margin-left: 12px;">총 ${pg.total_count}건</span>`;
|
||||
|
||||
pagination.innerHTML = html;
|
||||
}
|
||||
|
||||
function closeUsageHistoryModal() {
|
||||
document.getElementById('usageHistoryModal').classList.remove('show');
|
||||
}
|
||||
|
||||
// 환자 최근 처방 모달
|
||||
async function openPatientPrescriptionsModal(cusCode, patientName) {
|
||||
const modal = document.getElementById('patientPrescriptionsModal');
|
||||
const nameEl = document.getElementById('patientPrescriptionsName');
|
||||
const bodyEl = document.getElementById('patientPrescriptionsBody');
|
||||
|
||||
nameEl.textContent = patientName || cusCode;
|
||||
bodyEl.innerHTML = '<div class="purchase-empty"><div class="icon">⏳</div><p>처방 내역 조회 중...</p></div>';
|
||||
modal.classList.add('show');
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/patients/${cusCode}/recent-prescriptions`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success && data.prescriptions.length > 0) {
|
||||
let html = '';
|
||||
data.prescriptions.forEach(rx => {
|
||||
html += `
|
||||
<div class="rx-card" style="margin-bottom: 16px; padding: 16px; background: #f8fafc; border-radius: 12px; border-left: 4px solid #8b5cf6;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
|
||||
<div>
|
||||
<span style="font-weight: 600; color: #1e293b; font-size: 15px;">📅 ${rx.rx_date}</span>
|
||||
<span style="color: #64748b; font-size: 13px; margin-left: 12px;">${escapeHtml(rx.hospital_name || '')}</span>
|
||||
</div>
|
||||
<span style="color: #8b5cf6; font-size: 13px; font-weight: 500;">${escapeHtml(rx.doctor_name || '')}</span>
|
||||
</div>
|
||||
<table style="width: 100%; border-collapse: collapse; font-size: 13px;">
|
||||
<thead>
|
||||
<tr style="background: #e2e8f0;">
|
||||
<th style="padding: 8px; text-align: left; border-radius: 6px 0 0 6px;">약품명</th>
|
||||
<th style="padding: 8px; text-align: center; width: 80px;">용법</th>
|
||||
<th style="padding: 8px; text-align: center; width: 60px; border-radius: 0 6px 6px 0;">총량</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${rx.items.map(item => `
|
||||
<tr style="border-bottom: 1px solid #e2e8f0;">
|
||||
<td style="padding: 8px;">
|
||||
<div style="color: #334155; font-weight: 500;">${escapeHtml(item.drug_name)}</div>
|
||||
${item.category ? `<div style="font-size: 11px; color: #8b5cf6; margin-top: 2px;">${escapeHtml(item.category)}</div>` : ''}
|
||||
</td>
|
||||
<td style="padding: 8px; text-align: center; color: #475569; font-size: 12px;">${item.quantity}×${item.times}×${item.days}</td>
|
||||
<td style="padding: 8px; text-align: center; font-weight: 600; color: #8b5cf6;">${item.total_dose}</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
bodyEl.innerHTML = html;
|
||||
} else {
|
||||
bodyEl.innerHTML = '<div class="purchase-empty"><div class="icon">📭</div><p>최근 6개월간 처방 내역이 없습니다</p></div>';
|
||||
}
|
||||
} catch (err) {
|
||||
bodyEl.innerHTML = `<div class="purchase-empty"><div class="icon">❌</div><p>오류: ${err.message}</p></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function closePatientPrescriptionsModal() {
|
||||
document.getElementById('patientPrescriptionsModal').classList.remove('show');
|
||||
}
|
||||
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user