feat: 전화접수 관리에 [개발용 임시] 스캔 가능 바코드 후보 표 추가

지정판매소 판매의 dev-saleable-barcodes API를 재사용해, 주문 선택 시
그 판매소·주문 기준의 판매 테스트용 바코드 후보를 표로 표시한다.
바코드를 클릭하면 봉투코드 스캔칸에 자동 입력되어 테스트가 쉬워진다.
스캔 성공 시 후보 목록도 갱신(판매된 팩 제외). 개발 완료 후 제거 예정.
This commit is contained in:
taekyoungc
2026-07-02 19:31:35 +09:00
parent 130fb5ffdb
commit e198838998

View File

@@ -114,6 +114,31 @@
</div>
</div>
<!-- [개발용 임시] 선택 주문 판매소 기준 스캔 가능 바코드 후보 (개발 완료 후 이 블록 제거) -->
<div id="dev-saleable-panel" class="mt-2 hidden border border-amber-400 bg-amber-50/50 p-2 rounded-sm">
<p class="text-[11px] text-amber-900 mb-1 leading-relaxed">
<strong class="text-amber-950">[개발용 임시]</strong> 선택 주문의 판매소 기준 판매 테스트용 바코드 후보. <strong>바코드를 클릭하면 위 스캔칸에 입력</strong>됩니다. 개발 완료 후 이 블록과 API를 제거하세요.
</p>
<div class="max-h-52 overflow-auto border border-amber-300 bg-white">
<table class="w-full data-table text-xs">
<thead>
<tr>
<th class="w-28 text-left">출처</th>
<th class="w-44 text-center">바코드(대표)</th>
<th class="text-left">봉투 종류</th>
<th class="w-20 text-center">포장</th>
<th class="w-12 text-right">수량</th>
<th class="w-14 text-center">상태</th>
<th class="text-left">비고(낱장범위 등)</th>
</tr>
</thead>
<tbody id="dev-saleable-tbody">
<tr><td colspan="7" class="text-center text-gray-400 py-4">주문을 선택하면 목록이 표시됩니다.</td></tr>
</tbody>
</table>
</div>
</div>
<div class="mt-3">
<div class="flex items-center justify-between px-1 mb-1 text-sm">
<span class="font-semibold text-gray-700">포장 명세</span>
@@ -153,6 +178,8 @@
// 봉투코드 스캔(판매/포장) — CSRF 토큰(쿠키 방식, 매 요청 갱신)
// base_url() 절대경로를 현재 문서(동일 출처) 기준 경로로 변환 → 워크스페이스 iframe/다른 호스트 접근에도 안전
const scanApi = new URL('<?= base_url('bag/order/phone/manage/scan') ?>', window.location.href).pathname;
// [개발용 임시] 판매 가능 바코드 후보 API (지정판매소 판매의 dev API 재사용)
const devSaleableApi = new URL('<?= base_url('bag/sale/designated/dev-saleable-barcodes') ?>', window.location.href).pathname;
const csrfName = '<?= csrf_token() ?>';
let csrfHash = '<?= csrf_hash() ?>';
@@ -319,10 +346,56 @@
const msg = document.getElementById('scan-msg');
if (msg) msg.textContent = '';
}
// [개발용 임시] 선택 주문 판매소 기준 후보 바코드 표
loadDevSaleable(order.so_ds_idx, order.so_idx);
syncListHeight(); // 상세 카드 높이 확정 후 접수 리스트 높이를 맞춘다
}
// [개발용 임시] 스캔 가능 바코드 후보 로딩(선택 주문 판매소·주문 기준)
const devPanelEl = document.getElementById('dev-saleable-panel');
const devTbodyEl = document.getElementById('dev-saleable-tbody');
async function loadDevSaleable(dsIdx, soIdx) {
if (!devPanelEl || !devTbodyEl) return;
const idx = Number(dsIdx || 0);
if (!idx) { devPanelEl.classList.add('hidden'); return; }
devPanelEl.classList.remove('hidden');
devTbodyEl.innerHTML = '<tr><td colspan="7" class="text-center text-gray-400 py-4">불러오는 중…</td></tr>';
try {
let url = devSaleableApi + '?ds_idx=' + encodeURIComponent(String(idx));
if (Number(soIdx || 0) > 0) url += '&so_idx=' + encodeURIComponent(String(soIdx));
const res = await fetch(url, { credentials: 'same-origin' });
const data = await res.json();
if (!data.ok) { devTbodyEl.innerHTML = '<tr><td colspan="7" class="text-center text-red-600 py-4">' + esc(data.message || '조회 실패') + '</td></tr>'; return; }
const rows = Array.isArray(data.rows) ? data.rows : [];
if (!rows.length) { devTbodyEl.innerHTML = '<tr><td colspan="7" class="text-center text-gray-400 py-4">표시할 바코드가 없습니다.</td></tr>'; return; }
devTbodyEl.innerHTML = rows.map((r) => {
const code = String(r.code || '');
const codeCell = (code && code !== '-')
? '<button type="button" class="dev-pick text-blue-600 hover:underline font-mono" data-code="' + esc(code) + '">' + esc(code) + '</button>'
: '<span class="text-gray-400">' + esc(code) + '</span>';
return '<tr>'
+ '<td class="text-left pl-1">' + esc(r.source || '') + '</td>'
+ '<td class="text-center">' + codeCell + '</td>'
+ '<td class="text-left pl-1">' + esc((r.bag_code || '') + ' ' + (r.bag_name || '')) + '</td>'
+ '<td class="text-center">' + esc(r.unit || '') + '</td>'
+ '<td class="text-right pr-1">' + nf(r.qty || 0) + '</td>'
+ '<td class="text-center">' + esc(r.state || '') + '</td>'
+ '<td class="text-left pl-1">' + esc(r.extra || '') + '</td>'
+ '</tr>';
}).join('');
} catch (e) {
devTbodyEl.innerHTML = '<tr><td colspan="7" class="text-center text-red-600 py-4">네트워크 오류</td></tr>';
}
}
// 후보 바코드 클릭 → 스캔칸에 입력(개발 편의)
devTbodyEl?.addEventListener('click', (e) => {
const btn = e.target.closest('.dev-pick');
if (!btn) return;
const inp = document.getElementById('scan-input');
if (inp && !inp.disabled) { inp.value = btn.getAttribute('data-code') || ''; inp.focus(); }
});
// 봉투코드 스캔 → 즉시 판매·포장 처리 후 화면 갱신
const scanInputEl = document.getElementById('scan-input');
const scanMsgEl = document.getElementById('scan-msg');
@@ -386,6 +459,8 @@
}
// 접수 리스트의 '포장' 표시(O/X) 갱신
renderList();
// [개발용 임시] 후보 목록 갱신(방금 판매된 팩 제외)
loadDevSaleable(order.so_ds_idx, order.so_idx);
}
scanInputEl.value = '';
scanInputEl.focus();