diff --git a/app/Config/Manual.php b/app/Config/Manual.php index f17e3a6..251bb91 100644 --- a/app/Config/Manual.php +++ b/app/Config/Manual.php @@ -40,34 +40,37 @@ class Manual extends BaseConfig * "이 화면 설명" 버튼이 현재 경로로 알맞은 매뉴얼 페이지를 연다. * 더 긴(구체적) 접두가 우선하도록 길이 내림차순으로 매칭한다. * + * 값에 "slug#소제목힌트" 형식으로 적으면, 매뉴얼 창이 열릴 때 해당 소제목으로 + * 자동 스크롤하고 잠시 강조 표시한다(힌트는 그 페이지의 H2/H3 텍스트 일부와 일치). + * * @var array */ public array $screenHelp = [ - 'bag/order/phone' => 'sales', - 'bag/order' => 'order', - 'bag/bag-orders' => 'order', - 'bag/receiving' => 'order', - 'bag/bag-receivings' => 'order', - 'bag/inventory' => 'inventory', - 'bag/sale' => 'sales', - 'bag/sales' => 'sales', - 'bag/issue' => 'sales', - 'bag/bag-issues' => 'sales', - 'bag/bag-sales' => 'sales', - 'bag/shop-orders' => 'sales', + 'bag/order/phone' => 'sales#전화 주문 접수', + 'bag/order' => 'order#발주 등록', + 'bag/bag-orders' => 'order#발주 현황', + 'bag/receiving' => 'order#입고 처리', + 'bag/bag-receivings' => 'order#입고 현황', + 'bag/inventory' => 'inventory#재고 현황', + 'bag/sale' => 'sales#지정판매소 판매', + 'bag/sales' => 'sales#지정판매소 판매', + 'bag/issue' => 'sales#무료용 불출 처리', + 'bag/bag-issues' => 'sales#무료용 불출 처리', + 'bag/bag-sales' => 'sales#판매/반품 현황', + 'bag/shop-orders' => 'sales#전화 주문 접수', 'bag/flow' => 'reports', - 'bag/reports' => 'reports', + 'bag/reports' => 'reports#일계표', 'bag/analytics' => 'reports', - 'bag/designated-shops' => 'basic', - 'bag/bag-prices' => 'basic', - 'bag/prices' => 'basic', - 'bag/packaging-units' => 'basic', - 'bag/code-kinds' => 'basic', - 'bag/code-details' => 'basic', - 'bag/managers' => 'basic', - 'bag/companies' => 'basic', - 'bag/sales-agencies' => 'basic', - 'bag/free-recipients' => 'basic', + 'bag/designated-shops' => 'basic#지정판매소 관리', + 'bag/bag-prices' => 'basic#단가 관리', + 'bag/prices' => 'basic#단가 관리', + 'bag/packaging-units' => 'basic#포장 단위 관리', + 'bag/code-kinds' => 'basic#기본코드 관리', + 'bag/code-details' => 'basic#기본코드 관리', + 'bag/managers' => 'basic#그 밖의 기본정보', + 'bag/companies' => 'basic#그 밖의 기본정보', + 'bag/sales-agencies' => 'basic#그 밖의 기본정보', + 'bag/free-recipients' => 'basic#그 밖의 기본정보', 'bag/number-lookup' => 'codes', ]; } diff --git a/app/Helpers/admin_helper.php b/app/Helpers/admin_helper.php index aba61be..c01f69a 100644 --- a/app/Helpers/admin_helper.php +++ b/app/Helpers/admin_helper.php @@ -950,18 +950,28 @@ if (! function_exists('manual_help_url_for_path')) { return ''; } $map = config(\Config\Manual::class)->screenHelp ?? []; - $bestSlug = ''; - $bestLen = -1; - foreach ($map as $prefix => $slug) { + $bestVal = ''; + $bestLen = -1; + foreach ($map as $prefix => $val) { $p = strtolower((string) $prefix); if ($path === $p || str_starts_with($path . '/', $p . '/')) { if (strlen($p) > $bestLen) { - $bestLen = strlen($p); - $bestSlug = (string) $slug; + $bestLen = strlen($p); + $bestVal = (string) $val; } } } + if ($bestVal === '') { + return ''; + } - return $bestSlug !== '' ? base_url('bag/manual/' . $bestSlug) : ''; + // 값은 "slug" 또는 "slug#소제목힌트" 형식. 힌트가 있으면 ?hl= 로 전달해 해당 소제목으로 스크롤·강조. + [$slug, $hint] = array_pad(explode('#', $bestVal, 2), 2, null); + $url = base_url('bag/manual/' . $slug); + if ($hint !== null && trim($hint) !== '') { + $url .= '?hl=' . rawurlencode(trim($hint)); + } + + return $url; } } diff --git a/app/Views/admin/layout.php b/app/Views/admin/layout.php index 54894cc..9ee77b5 100644 --- a/app/Views/admin/layout.php +++ b/app/Views/admin/layout.php @@ -105,6 +105,11 @@ tailwind.config = { base_url('/')]) ?>
+
+ + 100% + +
· · 님 @@ -161,6 +166,25 @@ tailwind.config = { window.addEventListener('pageshow', function (e) { if (e.persisted) closeStuckOverlays(); }); window.addEventListener('pagehide', closeStuckOverlays); })(); + + // 글씨 크기 조절(A−/A+) — 본문 + 상단 대메뉴 + 좌측 사이드바에 zoom 적용. 사이트/워크스페이스와 배율 공유. + (function () { + var FONT_KEY = 'jrj_font_scale'; + var scaleSelectors = ['.portal-header', '.sidebar', '.work-main']; + function curScale() { var s = parseInt(localStorage.getItem(FONT_KEY) || '100', 10); return (s >= 70 && s <= 150) ? s : 100; } + function applyScale(s) { + s = Math.min(150, Math.max(70, s)); + try { localStorage.setItem(FONT_KEY, String(s)); } catch (e) {} + var z = s / 100; + scaleSelectors.forEach(function (sel) { var el = document.querySelector(sel); if (el) el.style.zoom = z; }); + var pct = document.getElementById('wsFontPct'); if (pct) pct.textContent = s + '%'; + } + applyScale(curScale()); + var plus = document.getElementById('wsFontPlus'), minus = document.getElementById('wsFontMinus'); + if (plus) plus.addEventListener('click', function () { applyScale(curScale() + 10); }); + if (minus) minus.addEventListener('click', function () { applyScale(curScale() - 10); }); + window.addEventListener('storage', function (e) { if (e.key === FONT_KEY) applyScale(curScale()); }); + })(); diff --git a/app/Views/bag/layout/embed.php b/app/Views/bag/layout/embed.php index b479673..7a9ab30 100644 --- a/app/Views/bag/layout/embed.php +++ b/app/Views/bag/layout/embed.php @@ -51,7 +51,7 @@ tailwind.config = { .data-table tbody tr:hover td { background-color: #f9fafb; } @media print { .no-print { display: none !important; } .embed-titlebar { display: none; } } /* 화면 설명 드로어(팝업) — 현재 화면 위 오른쪽에 겹쳐 띄움 */ - .help-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(460px, 92vw); background: #fff; box-shadow: -8px 0 26px rgba(0,0,0,.18); z-index: 9999; display: none; flex-direction: column; } + .help-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(920px, 92vw); background: #fff; box-shadow: -8px 0 26px rgba(0,0,0,.18); z-index: 9999; display: none; flex-direction: column; } .help-drawer.open { display: flex; } .help-drawer-head { display: flex; align-items: center; justify-content: space-between; padding: .5rem .75rem; background: #1a2b4b; color: #fff; font-size: .8rem; font-weight: 700; flex-shrink: 0; } .help-drawer-head .hd-btns { display: flex; gap: 4px; } @@ -137,7 +137,13 @@ tailwind.config = { function withEmbedUrl(url) { try { var x = new URL(url, location.href); x.searchParams.set('embed', '1'); return x.href; } catch (e) { return url; } } function openHelp(url) { var u = withEmbedUrl(url); - if (dFrame.getAttribute('data-src') !== u) { dFrame.src = u; dFrame.setAttribute('data-src', u); } + if (dFrame.getAttribute('data-src') !== u) { + // 새 URL → 재로드(로드 후 매뉴얼 자체 스크립트가 강조 실행) + dFrame.src = u; dFrame.setAttribute('data-src', u); + } else { + // 같은 URL → 재로드 안 함. 매뉴얼에 다시 강조하라고 알림(껐다 켜도 강조되도록) + try { dFrame.contentWindow.postMessage({ type: 'manual-hl' }, location.origin); } catch (e) {} + } var tab = document.getElementById('helpDrawerTab'); if (tab) tab.setAttribute('href', url); drawer.classList.add('open'); } @@ -160,9 +166,13 @@ tailwind.config = { // 드로어 폭 드래그 조절 (function () { var grip = document.getElementById('helpDrawerGrip'), dragging = false; - grip.addEventListener('mousedown', function (e) { e.preventDefault(); dragging = true; document.body.style.userSelect = 'none'; }); + // 드래그 중 iframe 이 마우스 이벤트를 가로채면(특히 좁힐 때) 멈추므로, 화면 전체 투명 오버레이로 이벤트를 가로챈다. + var ov = document.createElement('div'); + ov.style.cssText = 'position:fixed;inset:0;z-index:10000;cursor:col-resize;display:none;'; + document.body.appendChild(ov); + grip.addEventListener('mousedown', function (e) { e.preventDefault(); dragging = true; ov.style.display = 'block'; document.body.style.userSelect = 'none'; }); document.addEventListener('mousemove', function (e) { if (!dragging) return; var w = window.innerWidth - e.clientX; drawer.style.width = Math.min(window.innerWidth * 0.92, Math.max(300, w)) + 'px'; }); - document.addEventListener('mouseup', function () { dragging = false; document.body.style.userSelect = ''; }); + document.addEventListener('mouseup', function () { if (!dragging) return; dragging = false; ov.style.display = 'none'; document.body.style.userSelect = ''; }); })(); // 글씨 크기(zoom) — 상단바에서 조절한 값을 적용. localStorage 공유 + storage 이벤트로 실시간 반영. diff --git a/app/Views/bag/layout/portal.php b/app/Views/bag/layout/portal.php index 8698b8e..e49a5b4 100644 --- a/app/Views/bag/layout/portal.php +++ b/app/Views/bag/layout/portal.php @@ -217,7 +217,7 @@ tailwind.config = {