feat(rx-usage): 선호 도매상 컬럼 추가

- 테이블에 '선호도매상' 컬럼 추가
- 입고장 기반 최다/최근 주문 도매상 표시
- API: /api/order/drugs/preferred-vendors 연동
- Python 스크립트로 안전하게 수정
This commit is contained in:
thug0bin 2026-03-07 23:10:22 +09:00
parent a23e4bad43
commit 09948c234f

View File

@ -841,13 +841,14 @@
<th class="center">처방횟수</th>
<th class="center">투약량</th>
<th class="center" style="color:var(--accent-cyan);">주문량</th>
<th class="center" style="color:var(--accent-purple);font-size:11px;">선호도매상</th>
<th class="right">매출액</th>
<th class="center" style="width:90px">주문수량</th>
</tr>
</thead>
<tbody id="usageTableBody">
<tr>
<td colspan="8">
<td colspan="9">
<div class="loading-state">
<div class="loading-spinner"></div>
<div>데이터 로딩 중...</div>
@ -894,7 +895,38 @@
<script>
let usageData = [];
let cart = [];
let orderDataByKd = {}; // 도매상 주문량 합산 (KD코드별) - 지오영 + 수인
let orderDataByKd = {};
let preferredVendors = {}; // 약품별 선호 도매상
// 선호 도매상 표시
function getPreferredVendor(drugCode) {
const v = preferredVendors[drugCode];
if (!v || !v.success) return '-';
const recent = v.recent_vendor;
const most = v.most_frequent_vendor;
if (!recent && !most) return '-';
const shorten = (n) => n ? n.replace('강원','').replace('(주)','').replace('지점','').replace('약품','').substring(0,3) : '';
const rn = recent ? shorten(recent.vendor_name) : '';
const mn = most ? shorten(most.vendor_name) : '';
if (rn === mn && rn) return `<span style="color:#10b981" title="${most?.vendor_name}">${rn}</span>`;
let h = '';
if (mn) h += `<span style="color:#a855f7" title="최다(${most.order_count}회)">★${mn}</span>`;
if (rn && rn !== mn) h += `<br><span style="color:#888" title="최근">▸${rn}</span>`;
return h || '-';
}
// 선호 도매상 로드
async function loadPreferredVendors(codes) {
if (!codes || !codes.length) return;
try {
const r = await fetch('/api/order/drugs/preferred-vendors', {
method: 'POST', headers: {'Content-Type': 'application/json'},
body: JSON.stringify({drug_codes: codes, period: 365})
});
const d = await r.json();
if (d.success) { preferredVendors = d.results; renderTable(); }
} catch(e) { console.error('선호도매상 로드 실패:', e); }
} // 도매상 주문량 합산 (KD코드별) - 지오영 + 수인
// 초기화
document.addEventListener('DOMContentLoaded', function() {
@ -996,7 +1028,7 @@
const sort = document.getElementById('sortSelect').value;
document.getElementById('usageTableBody').innerHTML = `
<tr><td colspan="8">
<tr><td colspan="9">
<div class="loading-state">
<div class="loading-spinner"></div>
<div>데이터 로딩 중...</div>
@ -1021,9 +1053,11 @@
document.getElementById('resultCount').textContent = `(${data.items.length}개)`;
renderTable();
// 선호 도매상 로드 (백그라운드)
loadPreferredVendors(data.items.map(i => i.drug_code));
} else {
document.getElementById('usageTableBody').innerHTML = `
<tr><td colspan="8">
<tr><td colspan="9">
<div class="empty-state">
<div class="empty-icon">⚠️</div>
<div>오류: ${data.error}</div>
@ -1033,7 +1067,7 @@
})
.catch(err => {
document.getElementById('usageTableBody').innerHTML = `
<tr><td colspan="8">
<tr><td colspan="9">
<div class="empty-state">
<div class="empty-icon"></div>
<div>데이터 로드 실패</div>
@ -1048,7 +1082,7 @@
if (usageData.length === 0) {
tbody.innerHTML = `
<tr><td colspan="8">
<tr><td colspan="9">
<div class="empty-state">
<div class="empty-icon">💊</div>
<div>해당 기간 처방 내역이 없습니다</div>
@ -1084,6 +1118,7 @@
<td class="qty-cell" style="color:var(--text-secondary);">${item.prescription_count}건</td>
<td class="qty-cell ${qtyClass}">${item.total_dose}</td>
<td class="qty-cell" style="color:var(--accent-cyan);">${getOrderedQty(item.drug_code)}</td>
<td class="qty-cell" style="font-size:10px;">${getPreferredVendor(item.drug_code)}</td>
<td style="text-align:right;font-family:'JetBrains Mono',monospace;font-size:12px;">
${formatPrice(item.total_amount)}원
</td>