feat(animal-chat): APC 코드 2024년 체계 지원 및 피부약 2단계 추천
## APC 코드 체계 확장 - 기존: 023%만 검색 (~2023년 제품만) - 변경: 02% OR 92% + 13자리 검증 - 02%: 2023년 이전 item_seq (9자리) 기반 APC - 92%: 2024년 이후 item_seq (10자리) 기반 APC - 999% 등 청구프로그램 임의코드는 제외 ## 동물약 챗봇 피부약 추천 개선 - 피부약 2단계 추천 구조 추가 - 1차(치료): 의약품 (개시딘겔, 테르비덤 등) - 2차(보조케어): 의약외품 (스킨카솔 - 회복기 피부보호) - 스킨카솔은 의약외품임을 명시하여 치료제로 오인 방지 ## 기타 - RAG 테스트 스크립트 추가 - 수인약품 API 문서화
This commit is contained in:
@@ -48,6 +48,87 @@
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* ══════════════════ 주문량 툴팁 ══════════════════ */
|
||||
.order-qty-cell {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
.order-qty-tooltip {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
min-width: 140px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.2s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.order-qty-cell:hover .order-qty-tooltip {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
bottom: calc(100% + 8px);
|
||||
}
|
||||
.order-qty-tooltip::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border: 6px solid transparent;
|
||||
border-top-color: var(--border);
|
||||
}
|
||||
.order-qty-tooltip-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.order-qty-tooltip-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
.order-qty-tooltip-row:not(:last-child) {
|
||||
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
.order-qty-vendor {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.order-qty-vendor-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.order-qty-vendor-dot.geoyoung { background: #06b6d4; }
|
||||
.order-qty-vendor-dot.sooin { background: #a855f7; }
|
||||
.order-qty-vendor-dot.baekje { background: #f59e0b; }
|
||||
.order-qty-vendor-dot.dongwon { background: #22c55e; }
|
||||
.order-qty-value {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.order-qty-total {
|
||||
margin-top: 6px;
|
||||
padding-top: 6px;
|
||||
border-top: 1px solid var(--border);
|
||||
font-weight: 700;
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
/* ══════════════════ 헤더 ══════════════════ */
|
||||
.header {
|
||||
background: linear-gradient(135deg, #0891b2 0%, #06b6d4 50%, #22d3ee 100%);
|
||||
@@ -958,60 +1039,45 @@
|
||||
|
||||
let totalOrders = 0;
|
||||
|
||||
// 지오영 데이터 합산
|
||||
if (geoRes.success && geoRes.by_kd_code) {
|
||||
for (const [kd, data] of Object.entries(geoRes.by_kd_code)) {
|
||||
if (!orderDataByKd[kd]) {
|
||||
orderDataByKd[kd] = { product_name: data.product_name, spec: data.spec, boxes: 0, units: 0, sources: [] };
|
||||
}
|
||||
orderDataByKd[kd].boxes += data.boxes || 0;
|
||||
orderDataByKd[kd].units += data.units || 0;
|
||||
orderDataByKd[kd].sources.push('지오영');
|
||||
}
|
||||
totalOrders += geoRes.order_count || 0;
|
||||
console.log('🏭 지오영 주문량:', Object.keys(geoRes.by_kd_code).length, '품목,', geoRes.order_count, '건');
|
||||
}
|
||||
// 도매상 정보 (확장 가능)
|
||||
const vendorConfig = {
|
||||
geoyoung: { name: '지오영', icon: '🏭', res: geoRes },
|
||||
sooin: { name: '수인', icon: '💜', res: sooinRes },
|
||||
baekje: { name: '백제', icon: '💉', res: baekjeRes },
|
||||
dongwon: { name: '동원', icon: '🟠', res: dongwonRes }
|
||||
};
|
||||
|
||||
// 수인 데이터 합산
|
||||
if (sooinRes.success && sooinRes.by_kd_code) {
|
||||
for (const [kd, data] of Object.entries(sooinRes.by_kd_code)) {
|
||||
if (!orderDataByKd[kd]) {
|
||||
orderDataByKd[kd] = { product_name: data.product_name, spec: data.spec, boxes: 0, units: 0, sources: [] };
|
||||
// 각 도매상 데이터 합산 (상세 정보 포함)
|
||||
for (const [vendorId, config] of Object.entries(vendorConfig)) {
|
||||
const res = config.res;
|
||||
if (res.success && res.by_kd_code) {
|
||||
for (const [kd, data] of Object.entries(res.by_kd_code)) {
|
||||
if (!orderDataByKd[kd]) {
|
||||
orderDataByKd[kd] = {
|
||||
product_name: data.product_name,
|
||||
spec: data.spec,
|
||||
boxes: 0,
|
||||
units: 0,
|
||||
details: [] // 도매상별 상세 배열
|
||||
};
|
||||
}
|
||||
const boxes = data.boxes || 0;
|
||||
const units = data.units || 0;
|
||||
orderDataByKd[kd].boxes += boxes;
|
||||
orderDataByKd[kd].units += units;
|
||||
// 상세 정보 추가 (수량이 있는 경우만)
|
||||
if (units > 0 || boxes > 0) {
|
||||
orderDataByKd[kd].details.push({
|
||||
vendor: vendorId,
|
||||
name: config.name,
|
||||
boxes: boxes,
|
||||
units: units
|
||||
});
|
||||
}
|
||||
}
|
||||
orderDataByKd[kd].boxes += data.boxes || 0;
|
||||
orderDataByKd[kd].units += data.units || 0;
|
||||
orderDataByKd[kd].sources.push('수인');
|
||||
totalOrders += res.order_count || 0;
|
||||
console.log(`${config.icon} ${config.name} 주문량:`, Object.keys(res.by_kd_code).length, '품목,', res.order_count, '건');
|
||||
}
|
||||
totalOrders += sooinRes.order_count || 0;
|
||||
console.log('💜 수인 주문량:', Object.keys(sooinRes.by_kd_code).length, '품목,', sooinRes.order_count, '건');
|
||||
}
|
||||
|
||||
// 백제 데이터 합산
|
||||
if (baekjeRes.success && baekjeRes.by_kd_code) {
|
||||
for (const [kd, data] of Object.entries(baekjeRes.by_kd_code)) {
|
||||
if (!orderDataByKd[kd]) {
|
||||
orderDataByKd[kd] = { product_name: data.product_name, spec: data.spec, boxes: 0, units: 0, sources: [] };
|
||||
}
|
||||
orderDataByKd[kd].boxes += data.boxes || 0;
|
||||
orderDataByKd[kd].units += data.units || 0;
|
||||
orderDataByKd[kd].sources.push('백제');
|
||||
}
|
||||
totalOrders += baekjeRes.order_count || 0;
|
||||
console.log('💉 백제 주문량:', Object.keys(baekjeRes.by_kd_code).length, '품목,', baekjeRes.order_count, '건');
|
||||
}
|
||||
|
||||
// 동원 데이터 합산
|
||||
if (dongwonRes.success && dongwonRes.by_kd_code) {
|
||||
for (const [kd, data] of Object.entries(dongwonRes.by_kd_code)) {
|
||||
if (!orderDataByKd[kd]) {
|
||||
orderDataByKd[kd] = { product_name: data.product_name, spec: data.spec, boxes: 0, units: 0, sources: [] };
|
||||
}
|
||||
orderDataByKd[kd].boxes += data.boxes || 0;
|
||||
orderDataByKd[kd].units += data.units || 0;
|
||||
orderDataByKd[kd].sources.push('동원');
|
||||
}
|
||||
totalOrders += dongwonRes.order_count || 0;
|
||||
console.log('🟠 동원 주문량:', Object.keys(dongwonRes.by_kd_code).length, '품목,', dongwonRes.order_count, '건');
|
||||
}
|
||||
|
||||
console.log('📦 4사 합산 주문량:', Object.keys(orderDataByKd).length, '품목,', totalOrders, '건 주문');
|
||||
@@ -1025,14 +1091,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
// KD코드로 주문량 조회
|
||||
// KD코드로 주문량 조회 (툴팁 포함)
|
||||
let orderDataLoading = true; // 로딩 상태
|
||||
|
||||
function getOrderedQty(kdCode) {
|
||||
if (orderDataLoading) return '<span class="order-loading">···</span>';
|
||||
const order = orderDataByKd[kdCode];
|
||||
if (!order) return '-';
|
||||
return order.units.toLocaleString();
|
||||
if (!order || order.units === 0) return '-';
|
||||
|
||||
// 상세 정보가 없거나 1개만 있으면 단순 표시
|
||||
if (!order.details || order.details.length <= 1) {
|
||||
const vendorName = order.details && order.details[0] ? order.details[0].name : '';
|
||||
return `<span title="${vendorName}">${order.units.toLocaleString()}</span>`;
|
||||
}
|
||||
|
||||
// 2개 이상 도매상이면 툴팁 표시
|
||||
let tooltipHtml = `<div class="order-qty-tooltip">
|
||||
<div class="order-qty-tooltip-title">도매상별 주문</div>`;
|
||||
|
||||
for (const detail of order.details) {
|
||||
tooltipHtml += `
|
||||
<div class="order-qty-tooltip-row">
|
||||
<span class="order-qty-vendor">
|
||||
<span class="order-qty-vendor-dot ${detail.vendor}"></span>
|
||||
${detail.name}
|
||||
</span>
|
||||
<span class="order-qty-value">${detail.units.toLocaleString()}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
tooltipHtml += `
|
||||
<div class="order-qty-tooltip-row order-qty-total">
|
||||
<span>합계</span>
|
||||
<span>${order.units.toLocaleString()}</span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
return `<div class="order-qty-cell">
|
||||
${order.units.toLocaleString()}
|
||||
${tooltipHtml}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// ──────────────── 데이터 로드 ────────────────
|
||||
|
||||
Reference in New Issue
Block a user