From 19c70e42fb0315d4985a5f11bc613282d04cba6b Mon Sep 17 00:00:00 2001 From: thug0bin Date: Fri, 6 Mar 2026 11:59:13 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=8D=94=EB=B8=94=ED=81=B4=EB=A6=AD=20?= =?UTF-8?q?=EC=8B=9C=20=EC=A7=80=EC=98=A4=EC=98=81+=EC=88=98=EC=9D=B8=20?= =?UTF-8?q?=EB=8F=99=EC=8B=9C=20=EC=9E=AC=EA=B3=A0=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - openWholesaleModal: 두 도매상 동시 API 호출 - Promise.all로 병렬 조회 (빠른 응답) - 도매상별 섹션 구분 UI (지오영: 청록, 수인: 보라) - 각 도매상별 담기 버튼 - 수인은 단가 정보도 표시 --- backend/templates/admin_rx_usage.html | 306 ++++++++++++++++++-------- 1 file changed, 209 insertions(+), 97 deletions(-) diff --git a/backend/templates/admin_rx_usage.html b/backend/templates/admin_rx_usage.html index badb590..c61e6cc 100644 --- a/backend/templates/admin_rx_usage.html +++ b/backend/templates/admin_rx_usage.html @@ -1279,14 +1279,15 @@ if (e.key === 'Enter') loadUsageData(); }); - // ──────────────── 지오영 재고 조회 ──────────────── - let currentGeoyoungItem = null; + // ──────────────── 도매상 재고 조회 (지오영 + 수인) ──────────────── + let currentWholesaleItem = null; + window.wholesaleItems = { geoyoung: [], sooin: [] }; - function openGeoyoungModal(idx) { + function openWholesaleModal(idx) { const item = usageData[idx]; if (!item) return; - currentGeoyoungItem = item; + currentWholesaleItem = item; // 모달 열기 document.getElementById('geoModalProductName').textContent = item.product_name; @@ -1300,142 +1301,193 @@ document.getElementById('geoResultBody').innerHTML = `
-
지오영 재고 조회 중...
+
도매상 재고 조회 중... (지오영 + 수인)
`; + document.getElementById('geoSearchKeyword').style.display = 'none'; - // API 호출 (보험코드로 먼저 시도) - searchGeoyoung(item.drug_code, item.product_name); + // 두 도매상 동시 호출 + searchAllWholesalers(item.drug_code, item.product_name); } function closeGeoyoungModal() { document.getElementById('geoyoungModal').classList.remove('show'); - currentGeoyoungItem = null; + currentWholesaleItem = null; } - async function searchGeoyoung(kdCode, productName) { + async function searchAllWholesalers(kdCode, productName) { const resultBody = document.getElementById('geoResultBody'); + // 두 도매상 동시 호출 + const [geoResult, sooinResult] = await Promise.all([ + searchGeoyoungAPI(kdCode, productName), + searchSooinAPI(kdCode) + ]); + + // 결과 저장 + window.wholesaleItems = { + geoyoung: geoResult.items || [], + sooin: sooinResult.items || [] + }; + + // 통합 렌더링 + renderWholesaleResults(geoResult, sooinResult); + } + + async function searchGeoyoungAPI(kdCode, productName) { try { - // 1차: 보험코드(KD코드)로 검색 + // 1차: 보험코드로 검색 let response = await fetch(`/api/geoyoung/stock?kd_code=${encodeURIComponent(kdCode)}`); let data = await response.json(); // 결과 없으면 성분명으로 재검색 if (data.success && data.count === 0) { - document.getElementById('geoResultBody').innerHTML = ` -
-
-
성분명으로 재검색 중...
-
`; - response = await fetch(`/api/geoyoung/stock-by-name?product_name=${encodeURIComponent(productName)}`); data = await response.json(); } - if (!data.success) { - resultBody.innerHTML = ` -
-
❌ ${data.message || '조회 실패'}
-
`; - return; - } - - if (data.count === 0) { - resultBody.innerHTML = ` -
-
📭 지오영에 해당 제품이 없습니다
-
`; - return; - } - - // 검색어 표시 - if (data.extracted_ingredient) { - document.getElementById('geoSearchKeyword').textContent = `검색: "${data.extracted_ingredient}"`; - document.getElementById('geoSearchKeyword').style.display = 'block'; - } - - // 결과 렌더링 - renderGeoyoungResults(data.items); - + return data; } catch (err) { - resultBody.innerHTML = ` -
-
❌ 네트워크 오류: ${err.message}
-
`; + return { success: false, error: err.message, items: [] }; + } + } + + async function searchSooinAPI(kdCode) { + try { + const response = await fetch(`/api/sooin/stock?keyword=${encodeURIComponent(kdCode)}`); + const data = await response.json(); + return data; + } catch (err) { + return { success: false, error: err.message, items: [] }; } } - function renderGeoyoungResults(items) { + function renderWholesaleResults(geoResult, sooinResult) { const resultBody = document.getElementById('geoResultBody'); + const geoItems = geoResult.items || []; + const sooinItems = sooinResult.items || []; + // 재고 있는 것 먼저 정렬 - items.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock); + geoItems.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock); + sooinItems.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock); - let html = ` - - - - - - - - - `; + let html = ''; - items.forEach((item, idx) => { - const hasStock = item.stock > 0; - html += ` - - - - - - `; - }); + // ═══════ 지오영 섹션 ═══════ + html += `
+
+ 🏭 + 지오영 + ${geoItems.length}건 +
`; - html += '
제품명규격재고
-
- ${escapeHtml(item.product_name)} - ${item.insurance_code} -
-
${item.specification}${item.stock} - ${hasStock ? `` : ''} -
'; + if (geoItems.length > 0) { + html += ` + + `; + + geoItems.forEach((item, idx) => { + const hasStock = item.stock > 0; + html += ` + + + + + + `; + }); + + html += '
제품명규격재고
+
+ ${escapeHtml(item.product_name)} + ${item.insurance_code} +
+
${item.specification}${item.stock}${hasStock ? `` : ''}
'; + } else { + html += `
📭 검색 결과 없음
`; + } + html += ''; - // 전역에 저장 (담기용) - window.geoyoungItems = items; + // ═══════ 수인약품 섹션 ═══════ + html += `
+
+ 💊 + 수인약품 + ${sooinItems.length}건 +
`; + + if (sooinItems.length > 0) { + html += ` + + `; + + sooinItems.forEach((item, idx) => { + const hasStock = item.stock > 0; + html += ` + + + + + + + `; + }); + + html += '
제품명규격단가재고
+
+ ${escapeHtml(item.name)} + ${item.code} · ${item.manufacturer || ''} +
+
${item.spec || '-'}${item.price ? item.price.toLocaleString() + '원' : '-'}${item.stock}${hasStock ? `` : ''}
'; + } else { + html += `
📭 검색 결과 없음
`; + } + html += '
'; resultBody.innerHTML = html; } - function addGeoyoungToCart(idx) { - const item = window.geoyoungItems[idx]; - if (!item || !currentGeoyoungItem) return; + function addToCartFromWholesale(wholesaler, idx) { + const items = window.wholesaleItems[wholesaler]; + const item = items[idx]; + if (!item || !currentWholesaleItem) return; - // 수량 계산 (규격에서 숫자 추출) - const specMatch = item.specification.match(/(\d+)/); + // 규격에서 수량 추출 + const spec = wholesaler === 'geoyoung' ? item.specification : (item.spec || ''); + const specMatch = spec.match(/(\d+)/); const specQty = specMatch ? parseInt(specMatch[1]) : 1; // 필요 수량 계산 - const needed = currentGeoyoungItem.total_dose; + const needed = currentWholesaleItem.total_dose; const suggestedQty = Math.ceil(needed / specQty); - const qty = prompt(`주문 수량 (${item.specification} 기준)\n\n필요량: ${needed}개\n규격: ${specQty}개/단위\n추천: ${suggestedQty}단위 (${suggestedQty * specQty}개)`, suggestedQty); + const supplierName = wholesaler === 'geoyoung' ? '지오영' : '수인약품'; + const productName = wholesaler === 'geoyoung' ? item.product_name : item.name; + + const qty = prompt(`[${supplierName}] 주문 수량 (${spec} 기준)\n\n필요량: ${needed}개\n규격: ${specQty}개/단위\n추천: ${suggestedQty}단위 (${suggestedQty * specQty}개)`, suggestedQty); if (!qty || isNaN(qty)) return; - // 장바구니에 추가 (지오영 정보 포함) + // 장바구니에 추가 const cartItem = { - drug_code: currentGeoyoungItem.drug_code, - product_name: item.product_name, - supplier: '지오영', + drug_code: currentWholesaleItem.drug_code, + product_name: productName, + supplier: supplierName, qty: parseInt(qty), - specification: item.specification, - geoyoung_code: item.insurance_code + specification: spec, + wholesaler: wholesaler, + internal_code: wholesaler === 'geoyoung' ? item.internal_code : item.internal_code, + geoyoung_code: wholesaler === 'geoyoung' ? item.insurance_code : null, + sooin_code: wholesaler === 'sooin' ? item.code : null }; - // 기존 항목 체크 - const existing = cart.find(c => c.drug_code === currentGeoyoungItem.drug_code && c.specification === item.specification); + // 기존 항목 체크 (같은 도매상 + 같은 규격) + const existing = cart.find(c => + c.drug_code === currentWholesaleItem.drug_code && + c.specification === spec && + c.wholesaler === wholesaler + ); + if (existing) { existing.qty = parseInt(qty); } else { @@ -1444,24 +1496,28 @@ updateCartUI(); closeGeoyoungModal(); - showToast(`✅ ${item.product_name} (${item.specification}) ${qty}개 추가`, 'success'); + showToast(`✅ [${supplierName}] ${productName} (${spec}) ${qty}개 추가`, 'success'); } - // 테이블 행 더블클릭으로 지오영 모달 열기 + // 하위 호환 (기존 함수명 유지) + function openGeoyoungModal(idx) { openWholesaleModal(idx); } + function addGeoyoungToCart(idx) { addToCartFromWholesale('geoyoung', idx); } + + // 테이블 행 더블클릭으로 도매상 모달 열기 document.addEventListener('dblclick', function(e) { const row = e.target.closest('tr[data-idx]'); if (row) { const idx = parseInt(row.dataset.idx); - openGeoyoungModal(idx); + openWholesaleModal(idx); } }); - +
-

🏭 지오영 재고 조회

+

📦 도매상 재고 조회

@@ -1649,6 +1705,62 @@ background: #0891b2; transform: scale(1.05); } + .geo-add-btn.sooin { + background: var(--accent-purple); + } + .geo-add-btn.sooin:hover { + background: #7c3aed; + } + .geo-price { + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + color: var(--text-secondary); + } + + /* 도매상 섹션 구분 */ + .ws-section { + margin-bottom: 20px; + } + .ws-section:last-child { + margin-bottom: 0; + } + .ws-header { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + border-radius: 8px; + margin-bottom: 8px; + font-weight: 600; + } + .ws-header.geoyoung { + background: linear-gradient(135deg, rgba(6, 182, 212, 0.2), rgba(8, 145, 178, 0.1)); + border-left: 3px solid var(--accent-cyan); + } + .ws-header.sooin { + background: linear-gradient(135deg, rgba(168, 85, 247, 0.2), rgba(124, 58, 237, 0.1)); + border-left: 3px solid var(--accent-purple); + } + .ws-icon { + font-size: 18px; + } + .ws-name { + flex: 1; + font-size: 14px; + } + .ws-count { + font-size: 12px; + color: var(--text-muted); + background: rgba(255,255,255,0.1); + padding: 2px 8px; + border-radius: 10px; + } + .ws-empty { + text-align: center; + padding: 20px; + color: var(--text-muted); + font-size: 13px; + } /* 주문 확인 모달 */ .order-modal {