크롤러 (utils/yakkok_crawler.py): - yakkok.com에서 제품 검색 및 이미지 추출 - MSSQL 오늘 판매 품목 자동 조회 - base64 변환 후 SQLite 저장 - CLI 지원 (--today, --product) DB (product_images.db): - 바코드, 제품명, 이미지(base64), 상태 저장 - 크롤링 로그 테이블 어드민 페이지 (/admin/product-images): - 이미지 목록/검색/필터 - 통계 (성공/실패/대기) - 상세 보기/삭제 - 오늘 판매 제품 일괄 크롤링 API: - GET /api/admin/product-images - GET /api/admin/product-images/<barcode> - POST /api/admin/product-images/crawl-today - DELETE /api/admin/product-images/<barcode>
515 lines
12 KiB
HTML
515 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>스마트헬스케어 사업제안서</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;600;700&display=swap');
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
line-height: 1.8;
|
|
color: #1e293b;
|
|
max-width: 210mm;
|
|
margin: 0 auto;
|
|
padding: 20mm;
|
|
background: #fff;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
color: #6366f1;
|
|
margin: 40px 0 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 3px solid #6366f1;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
color: #334155;
|
|
margin: 35px 0 15px;
|
|
padding-bottom: 8px;
|
|
border-bottom: 2px solid #e2e8f0;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: #475569;
|
|
margin: 25px 0 12px;
|
|
}
|
|
|
|
h4 {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: #64748b;
|
|
margin: 20px 0 10px;
|
|
}
|
|
|
|
p {
|
|
margin: 12px 0;
|
|
text-align: justify;
|
|
}
|
|
|
|
blockquote {
|
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
border-left: 4px solid #6366f1;
|
|
padding: 16px 20px;
|
|
margin: 20px 0;
|
|
border-radius: 0 8px 8px 0;
|
|
font-style: italic;
|
|
color: #475569;
|
|
}
|
|
|
|
code {
|
|
background: #f1f5f9;
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
font-family: 'Consolas', 'Monaco', monospace;
|
|
font-size: 13px;
|
|
color: #dc2626;
|
|
}
|
|
|
|
pre {
|
|
background: #1e293b;
|
|
color: #e2e8f0;
|
|
padding: 20px;
|
|
border-radius: 12px;
|
|
overflow-x: auto;
|
|
margin: 20px 0;
|
|
font-size: 12px;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
pre code {
|
|
background: none;
|
|
color: inherit;
|
|
padding: 0;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 20px 0;
|
|
font-size: 14px;
|
|
}
|
|
|
|
th {
|
|
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
|
color: #fff;
|
|
padding: 12px 16px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
}
|
|
|
|
td {
|
|
padding: 12px 16px;
|
|
border-bottom: 1px solid #e2e8f0;
|
|
}
|
|
|
|
tr:nth-child(even) {
|
|
background: #f8fafc;
|
|
}
|
|
|
|
ul, ol {
|
|
margin: 15px 0;
|
|
padding-left: 25px;
|
|
}
|
|
|
|
li {
|
|
margin: 8px 0;
|
|
}
|
|
|
|
hr {
|
|
border: none;
|
|
height: 2px;
|
|
background: linear-gradient(90deg, #6366f1, #8b5cf6, #ec4899);
|
|
margin: 40px 0;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
strong {
|
|
color: #334155;
|
|
font-weight: 600;
|
|
}
|
|
|
|
em {
|
|
color: #64748b;
|
|
}
|
|
|
|
/* 첫 페이지 타이틀 */
|
|
h1:first-of-type {
|
|
font-size: 32px;
|
|
text-align: center;
|
|
border-bottom: none;
|
|
margin-top: 60px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
h1:first-of-type + blockquote {
|
|
text-align: center;
|
|
border-left: none;
|
|
background: none;
|
|
font-size: 18px;
|
|
margin-bottom: 60px;
|
|
}
|
|
|
|
/* 프린트 스타일 */
|
|
@media print {
|
|
body {
|
|
padding: 15mm;
|
|
}
|
|
|
|
pre {
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
h1, h2, h3 {
|
|
page-break-after: avoid;
|
|
}
|
|
|
|
table, pre, blockquote {
|
|
page-break-inside: avoid;
|
|
}
|
|
}
|
|
|
|
/* 페이지 구분 */
|
|
.page-break {
|
|
page-break-before: always;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1 id="apc">동물약 APC 매핑 가이드</h1>
|
|
<blockquote>
|
|
<p>최종 업데이트: 2026-03-02</p>
|
|
</blockquote>
|
|
<h2 id="_1">개요</h2>
|
|
<p>POS(PIT3000)의 동물약 제품을 APDB의 APC 코드와 매핑하여 제품 정보(용법, 용량, 주의사항) 및 이미지를 표시하기 위한 작업 가이드.</p>
|
|
<hr />
|
|
<h2 id="_2">현재 상태</h2>
|
|
<h3 id="_3">매핑 현황</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>구분</th>
|
|
<th>개수</th>
|
|
<th>비율</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>동물약 총</td>
|
|
<td>39개</td>
|
|
<td>100%</td>
|
|
</tr>
|
|
<tr>
|
|
<td>APC 매핑됨</td>
|
|
<td>7개</td>
|
|
<td>18%</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>APC 미매핑</strong></td>
|
|
<td><strong>32개</strong></td>
|
|
<td><strong>82%</strong></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3 id="_4">매핑 완료 제품</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>POS 제품명</th>
|
|
<th>DrugCode</th>
|
|
<th>APC</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>(판)복합개시딘</td>
|
|
<td>LB000003140</td>
|
|
<td>0231093520106</td>
|
|
</tr>
|
|
<tr>
|
|
<td>안텔민킹(5kg이상)</td>
|
|
<td>LB000003158</td>
|
|
<td>0230237810109</td>
|
|
</tr>
|
|
<tr>
|
|
<td>안텔민뽀삐(5kg이하)</td>
|
|
<td>LB000003157</td>
|
|
<td>0230237010107</td>
|
|
</tr>
|
|
<tr>
|
|
<td>파라캅L(5kg이상)</td>
|
|
<td>LB000003159</td>
|
|
<td>0230338510101</td>
|
|
</tr>
|
|
<tr>
|
|
<td>파라캅S(5kg이하)</td>
|
|
<td>LB000003160</td>
|
|
<td>0230347110106</td>
|
|
</tr>
|
|
<tr>
|
|
<td>세레니아정16mg(개멀미약)</td>
|
|
<td>LB000003353</td>
|
|
<td>0231884610109</td>
|
|
</tr>
|
|
<tr>
|
|
<td>세레니아정24mg(개멀미약)</td>
|
|
<td>LB000003354</td>
|
|
<td>0231884620107</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr />
|
|
<h2 id="_5">매핑 구조</h2>
|
|
<h3 id="_6">데이터베이스 연결</h3>
|
|
<pre><code>MSSQL (192.168.0.4\PM2014) PostgreSQL (192.168.0.87:5432)
|
|
┌─────────────────────────┐ ┌─────────────────────────┐
|
|
│ PM_DRUG.CD_GOODS │ │ apdb_master.apc │
|
|
│ - DrugCode │ │ - apc (PK) │
|
|
│ - GoodsName │ │ - product_name │
|
|
│ - BARCODE │ │ - image_url1 │
|
|
│ │ │ - llm_pharm (JSONB) │
|
|
├─────────────────────────┤ └─────────────────────────┘
|
|
│ PM_DRUG.CD_ITEM_UNIT_ │
|
|
│ MEMBER │
|
|
│ - DRUGCODE (FK) │
|
|
│ - CD_CD_BARCODE ◀───────┼── APC 코드 저장 (023%로 시작)
|
|
│ - CHANGE_DATE │
|
|
└─────────────────────────┘
|
|
</code></pre>
|
|
<h3 id="apc_1">APC 매핑 방식</h3>
|
|
<ol>
|
|
<li><code>CD_ITEM_UNIT_MEMBER</code> 테이블에 <strong>추가 바코드</strong>로 APC 등록</li>
|
|
<li>기존 바코드는 유지, APC를 별도 레코드로 INSERT</li>
|
|
<li>APC 코드는 <code>023%</code>로 시작 (식별자)</li>
|
|
</ol>
|
|
<hr />
|
|
<h2 id="11">1:1 매핑 가능 후보</h2>
|
|
<h3 id="1">✅ 확실한 매핑 (1개)</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>POS 제품명</th>
|
|
<th>DrugCode</th>
|
|
<th>APC</th>
|
|
<th>APDB 제품명</th>
|
|
<th>이미지</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>제스타제(10정)</strong></td>
|
|
<td>LB000003146</td>
|
|
<td>8809720800455</td>
|
|
<td>제스타제</td>
|
|
<td>✅ 있음</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3 id="1_1">⚠️ 검토 필요 (1개)</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>POS 제품명</th>
|
|
<th>DrugCode</th>
|
|
<th>APC 후보</th>
|
|
<th>비고</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>안텔민</td>
|
|
<td>S0000001</td>
|
|
<td>0230237800003</td>
|
|
<td>"안텔민킹"과 "안텔민뽀삐"는 이미 별도 매핑됨. 이 제품이 무엇인지 확인 필요</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3 id="apdb-3">❌ APDB에 없음 (3개)</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>POS 제품명</th>
|
|
<th>사유</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>(판)클라펫정50(100정)</td>
|
|
<td>APDB엔 "클라펫 정"만 있음 (함량 불일치)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>넥스가드xs(2~3.5kg)</td>
|
|
<td>사이즈별 APC 없음</td>
|
|
</tr>
|
|
<tr>
|
|
<td>캐치원캣(2.5~7.5kg)/고양이</td>
|
|
<td>APDB에 캐치원 자체가 없음</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr />
|
|
<h2 id="1n-27">1:N 매핑 필요 제품 (27개)</h2>
|
|
<p>사이즈별로 세분화된 제품들. 하나의 APDB APC에 여러 POS 제품을 매핑해야 함.</p>
|
|
<h3 id="_7">브랜드별 현황</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>브랜드</th>
|
|
<th>POS 제품 수</th>
|
|
<th>APDB 존재</th>
|
|
<th>비고</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>다이로하트</td>
|
|
<td>3개 (SS/S/M)</td>
|
|
<td>✅</td>
|
|
<td>다이로하트 츄어블 정</td>
|
|
</tr>
|
|
<tr>
|
|
<td>하트세이버</td>
|
|
<td>4개 (mini/S/M/L)</td>
|
|
<td>✅</td>
|
|
<td>하트세이버 플러스 츄어블</td>
|
|
</tr>
|
|
<tr>
|
|
<td>하트웜솔루션</td>
|
|
<td>2개 (S/M)</td>
|
|
<td>❌</td>
|
|
<td>APDB에 없음</td>
|
|
</tr>
|
|
<tr>
|
|
<td>리펠로</td>
|
|
<td>2개 (S/M)</td>
|
|
<td>✅</td>
|
|
<td>리펠로액 (이미지 있음!)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>캐치원</td>
|
|
<td>5개 (SS/S/M/L/캣)</td>
|
|
<td>❌</td>
|
|
<td>APDB에 없음</td>
|
|
</tr>
|
|
<tr>
|
|
<td>셀라이트</td>
|
|
<td>5개 (SS/S/M/L/XL)</td>
|
|
<td>✅</td>
|
|
<td>셀라이트 액</td>
|
|
</tr>
|
|
<tr>
|
|
<td>넥스가드</td>
|
|
<td>2개 (xs/L)</td>
|
|
<td>✅</td>
|
|
<td>넥스가드 스펙트라</td>
|
|
</tr>
|
|
<tr>
|
|
<td>가드닐</td>
|
|
<td>3개 (S/M/L)</td>
|
|
<td>✅</td>
|
|
<td>가드닐 액</td>
|
|
</tr>
|
|
<tr>
|
|
<td>심피드</td>
|
|
<td>2개 (M/L)</td>
|
|
<td>❌</td>
|
|
<td>APDB에 없음</td>
|
|
</tr>
|
|
<tr>
|
|
<td>하트캅</td>
|
|
<td>1개</td>
|
|
<td>✅</td>
|
|
<td>하트캅-츄어블 정</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<hr />
|
|
<h2 id="apdb">APDB 통계</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>항목</th>
|
|
<th>수치</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>전체 APC</td>
|
|
<td>16,326개</td>
|
|
</tr>
|
|
<tr>
|
|
<td>이미지 있음</td>
|
|
<td>73개 (0.4%)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>LLM 정보 있음</td>
|
|
<td>81개 (0.5%)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>동물 관련 키워드</td>
|
|
<td>~200개</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>⚠️ <strong>주의:</strong> APDB에 이미지가 거의 없음. 이미지 표시가 목적이라면 다른 소스 필요.</p>
|
|
<hr />
|
|
<h2 id="_8">매핑 스크립트</h2>
|
|
<h3 id="_9">매핑 후보 찾기</h3>
|
|
<pre><code class="language-bash">python backend/scripts/batch_apc_matching.py
|
|
</code></pre>
|
|
<h3 id="11_1">1:1 매핑 가능 후보 추출</h3>
|
|
<pre><code class="language-bash">python backend/scripts/find_1to1_candidates.py
|
|
</code></pre>
|
|
<h3 id="_10">매핑 실행 (수동)</h3>
|
|
<pre><code class="language-python"># backend/scripts/batch_insert_apc.py 참고
|
|
MAPPINGS = [
|
|
('제스타제(10정)', 'LB000003146', '8809720800455'),
|
|
]
|
|
</code></pre>
|
|
<h3 id="insert">INSERT 쿼리 예시</h3>
|
|
<pre><code class="language-sql">INSERT INTO CD_ITEM_UNIT_MEMBER (
|
|
DRUGCODE, CD_CD_UNIT, CD_NM_UNIT, CD_MY_UNIT, CD_IN_UNIT,
|
|
CD_CD_BARCODE, CD_CD_POS, CHANGE_DATE
|
|
) VALUES (
|
|
'LB000003146', -- DrugCode
|
|
'015', -- 단위코드
|
|
1.0, -- 단위명
|
|
<기존값>, -- CD_MY_UNIT (기존 레코드에서 복사)
|
|
<기존값>, -- CD_IN_UNIT (기존 레코드에서 복사)
|
|
'8809720800455', -- APC 바코드
|
|
'',
|
|
'20260302' -- 변경일자
|
|
)
|
|
</code></pre>
|
|
<hr />
|
|
<h2 id="_11">다음 단계</h2>
|
|
<ol>
|
|
<li><strong>제스타제</strong> 1:1 매핑 실행</li>
|
|
<li><strong>안텔민(S0000001)</strong> 제품 확인 후 결정</li>
|
|
<li>1:N 매핑 정책 결정 (사이즈별 제품 → 동일 APC?)</li>
|
|
<li>이미지 소스 대안 검토 (필요시)</li>
|
|
</ol>
|
|
<hr />
|
|
<h2 id="_12">관련 파일</h2>
|
|
<ul>
|
|
<li><code>backend/db/dbsetup.py</code> - DB 연결 설정</li>
|
|
<li><code>backend/scripts/batch_apc_matching.py</code> - 매칭 후보 찾기</li>
|
|
<li><code>backend/scripts/batch_insert_apc.py</code> - 매핑 실행</li>
|
|
<li><code>backend/scripts/find_1to1_candidates.py</code> - 1:1 후보 추출</li>
|
|
<li><code>backend/app.py</code> - <code>_get_animal_drugs()</code>, <code>_get_animal_drug_rag()</code></li>
|
|
</ul>
|
|
</body>
|
|
</html> |