feat: 전화접수 관리·주문 개선 + 매뉴얼 화면 바로가기

- 전화접수 관리: 배달일 기준 조회, 컬럼 보강(구분/포장 O·X/결제/수령/입금/총금액/취소),
  헤더 정렬, 배달일 수정 저장, 포장 명세·포장량 수정, 입금자 영수증 출력
- 전화 주문 접수: 행추가 → 일괄표(카테고리 그룹·포장 헤더)
- 매뉴얼 소제목에 '화면 열기' 바로가기(실제 GET 라우트만 연결)
- shop_order_item.soi_packed_qty 컬럼 추가(SQL)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
taekyoungc
2026-06-25 14:31:21 +09:00
parent 8e767ff234
commit acce968f9c
8 changed files with 435 additions and 143 deletions

View File

@@ -44,11 +44,15 @@ $searchQ = (string) (service('request')->getGet('q') ?? '');
.manual-prose tbody tr:nth-child(even) td { background: #f9fafb; }
.manual-prose hr { margin: 1.6rem 0; border: 0; border-top: 1px solid #e5e7eb; }
.manual-toc a.active { background: #1a2b4b; color: #fff; font-weight: 700; }
/* 소제목 옆 "화면 열기" 바로가기 */
.manual-jump { display: inline-flex; align-items: center; gap: 4px; margin-left: 8px; vertical-align: middle; font-size: 0.72rem; font-weight: 700; color: #1d4ed8; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 9999px; padding: 2px 9px; text-decoration: none; cursor: pointer; white-space: nowrap; }
.manual-jump:hover { background: #1d4ed8; color: #fff; border-color: #1d4ed8; }
.manual-jump i { font-size: 0.65rem; }
/* "이 화면 설명"으로 들어왔을 때 해당 소제목 강조 */
.manual-prose h2.hl-flash, .manual-prose h3.hl-flash { background: #fef9c3; box-shadow: -6px 0 0 #fef9c3, 6px 0 0 #fef9c3; border-radius: 4px; animation: hlFlash 2.6s ease-out 1; }
@keyframes hlFlash { 0%, 45% { background: #fde047; box-shadow: -6px 0 0 #fde047, 6px 0 0 #fde047; } 100% { background: transparent; box-shadow: -6px 0 0 transparent, 6px 0 0 transparent; } }
@media print {
.manual-toc, .manual-actions, .manual-nav { display: none !important; }
.manual-toc, .manual-actions, .manual-nav, .manual-jump { display: none !important; }
.manual-layout { display: block !important; }
.manual-prose { max-width: none; }
}
@@ -111,6 +115,8 @@ $searchQ = (string) (service('request')->getGet('q') ?? '');
var SEARCH_URL = location.origin + <?= json_encode((string) parse_url(base_url('bag/manual/search'), PHP_URL_PATH), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
var BASE = location.origin + <?= json_encode((string) parse_url(base_url('bag/manual/'), PHP_URL_PATH), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
var Q0 = <?= json_encode($searchQ, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS) ?>;
// 이 매뉴얼 페이지가 설명하는 화면 바로가기 목록 [{hint, url}, ...]
var JUMPS = <?= json_encode($jumps ?? [], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS) ?>;
// "이 화면 설명"으로 들어온 경우: 해당 소제목으로 스크롤 + 강조.
// 드로어를 껐다 다시 켜도(같은 URL이라 iframe 재로드 안 됨) 부모가 보낸 메시지로 다시 강조한다.
var hlFlashTimer = null;
@@ -140,6 +146,41 @@ $searchQ = (string) (service('request')->getGet('q') ?? '');
if (e.origin !== location.origin) return;
if (e.data && e.data.type === 'manual-hl') runHl();
});
// 해당 화면으로 이동: 워크스페이스(탭) 안이면 새 탭으로, 아니면 최상위 창을 이동.
function openScreen(url, title) {
try { if (window.top && typeof window.top.wsOpenTab === 'function') { window.top.wsOpenTab(url, title); return; } } catch (e) {}
try { if (window.parent && typeof window.parent.wsOpenTab === 'function') { window.parent.wsOpenTab(url, title); return; } } catch (e) {}
try { window.top.location.href = url; } catch (e) { window.location.href = url; }
}
// 각 소제목(h2/h3) 옆에 "화면 열기" 바로가기 버튼을 붙인다(hint 매칭).
(function attachJumps() {
if (!JUMPS || !JUMPS.length) return;
var prose = document.querySelector('.manual-prose');
if (!prose) return;
var norm = function (s) { return String(s || '').replace(/\s+/g, ' ').trim().toLowerCase(); };
var heads = prose.querySelectorAll('h2, h3');
JUMPS.forEach(function (j) {
var needle = norm(j.hint);
if (!needle || !j.url) return;
for (var i = 0; i < heads.length; i++) {
var h = heads[i];
if (h.getAttribute('data-jump')) continue; // 한 제목엔 하나만
if (norm(h.textContent).indexOf(needle) < 0) continue;
var label = (h.textContent || '화면').trim(); // 버튼 추가 전 제목 확보
var url = j.url;
var a = document.createElement('a');
a.className = 'manual-jump';
a.href = url;
a.title = '이 화면으로 이동';
a.innerHTML = '<i class="fa-solid fa-arrow-up-right-from-square"></i> 화면 열기';
a.addEventListener('click', function (ev) { ev.preventDefault(); openScreen(url, label); });
h.appendChild(a);
h.setAttribute('data-jump', '1');
break;
}
});
})();
var input = document.getElementById('manualSearchInput');
var box = document.getElementById('manualSearchResults');