From 77ce86f5eddd6ac7e778f96644a7e24af2679324 Mon Sep 17 00:00:00 2001 From: king Date: Fri, 26 Jun 2026 17:17:04 +0900 Subject: [PATCH] =?UTF-8?q?feat(dispatch):=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EA=B0=80=EB=8F=85=EC=84=B1=20=E2=80=94=20?= =?UTF-8?q?=EC=86=A1=EC=9E=A5=20=EC=A1=B0=ED=9A=8C=20=EB=A7=81=ED=81=AC?= =?UTF-8?q?=C2=B7=ED=83=9D=EB=B0=B0=EC=82=AC=20=EB=B0=B0=EC=A7=80=C2=B7?= =?UTF-8?q?=EC=A4=84=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - api_search: 결과에 courier_tracking_url 주입(송장 클릭 시 조회 페이지) - batches.html: Order/Pkg/송장 한 줄씩, 글자 확대, 송장번호·날짜·쇼핑몰 굵게, 송장 오른쪽 배송사 배지, 송장번호 클릭 → 배송사 조회 새 탭 Co-Authored-By: Claude Opus 4.8 --- app/modules/dispatch/router.py | 8 ++- .../dispatch/templates/dispatch/batches.html | 57 ++++++++++++++----- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/app/modules/dispatch/router.py b/app/modules/dispatch/router.py index 9aa8148..31eb161 100644 --- a/app/modules/dispatch/router.py +++ b/app/modules/dispatch/router.py @@ -726,7 +726,13 @@ async def api_search( query = (q or "").strip() if len(query) < 2: return JSONResponse({"query": query, "results": []}) - return JSONResponse({"query": query, "results": st.search_parcels(query=query)}) + results = st.search_parcels(query=query) + # 송장 조회 딥링크는 배송사 맵(store)에서 만든다 — 프런트엔 맵이 없다. + for r in results: + r["tracking_url"] = store.courier_tracking_url( + r.get("tracking_id", ""), r.get("shipping_provider", "") + ) + return JSONResponse({"query": query, "results": results}) @router.get("/health") diff --git a/app/modules/dispatch/templates/dispatch/batches.html b/app/modules/dispatch/templates/dispatch/batches.html index 5c220df..2935422 100644 --- a/app/modules/dispatch/templates/dispatch/batches.html +++ b/app/modules/dispatch/templates/dispatch/batches.html @@ -29,16 +29,25 @@ .dsp-q-clear { position:absolute;right:8px;top:50%;transform:translateY(-50%);border:0;background:transparent;color:#94a3b8;font-size:18px;cursor:pointer;line-height:1;padding:0 4px;display:none; } .dsp-search-results { position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:40;background:#fff;border:1px solid #e2e8f0;border-radius:10px;box-shadow:0 8px 24px rgba(15,23,42,.12);max-height:64vh;overflow:auto;display:none;padding:6px; } .dsp-search-results.open { display:block; } - .dsp-hit { border-radius:8px;padding:9px 10px;display:flex;justify-content:space-between;gap:12px;align-items:flex-start; } + .dsp-hit { border-radius:8px;padding:11px 12px;display:flex;justify-content:space-between;gap:12px;align-items:flex-start; } .dsp-hit + .dsp-hit { border-top:1px solid #f1f5f9; } .dsp-hit:hover { background:#f8fafc; } - .dsp-hit-name { font-weight:700;font-size:14px;color:#0f172a; } - .dsp-hit-meta { font-size:12.5px;color:#475569;margin-top:2px;line-height:1.5; } - .dsp-hit-meta code { background:#f1f5f9;padding:1px 5px;border-radius:4px;font-size:12px; } + .dsp-hit-body { min-width:0; } + .dsp-hit-name { font-weight:700;font-size:17px;color:#0f172a; } + .dsp-hit-meta { font-size:14px;color:#475569;margin-top:3px;line-height:1.5; } + /* Order / Pkg / 송장 — 한 줄씩 */ + .dsp-id { font-size:14.5px;margin-top:4px;display:flex;gap:8px;align-items:baseline;flex-wrap:wrap; } + .dsp-id-k { color:#94a3b8;font-size:12px;min-width:42px;flex:0 0 auto; } + .dsp-id code { background:#f1f5f9;padding:2px 7px;border-radius:5px;font-size:14px;color:#0f172a; } + .dsp-id-track code { font-weight:700; } + .dsp-track-lnk { text-decoration:none; } + .dsp-track-lnk code { color:#4f46e5;text-decoration:underline;cursor:pointer; } + .dsp-track-lnk:hover code { background:#e0e7ff; } + .dsp-courier { font-size:12.5px;font-weight:600;color:#475569;background:#eef2ff;border:1px solid #c7d2fe;border-radius:999px;padding:1px 9px; } .dsp-hit mark { background:#fde68a;padding:0 1px;border-radius:2px; } - .dsp-hit-batch { font-size:11.5px;color:#64748b;margin-top:3px; } + .dsp-hit-batch { font-size:13px;color:#475569;margin-top:5px; } .dsp-hit-go { white-space:nowrap;flex:0 0 auto;align-self:center; } - .dsp-hit-empty { color:#94a3b8;font-size:13.5px;padding:10px; } + .dsp-hit-empty { color:#94a3b8;font-size:14.5px;padding:11px; } {% endblock %} @@ -294,11 +303,26 @@ } function en() { return (window.dspLang && window.dspLang() === 'en'); } + function idLine(label, value, q) { + if (!value) return ''; + return '
' + label + '' + + '' + hi(value, q) + '
'; + } + function trackLine(r, q) { + if (!r.tracking_id) return ''; + var num = '' + hi(r.tracking_id, q) + ''; + // 송장번호 클릭 → 배송사 조회 페이지(딥링크 있으면). + var inner = r.tracking_url + ? '' + num + '' + : num; + var courier = r.shipping_provider + ? '' + esc(r.shipping_provider) + '' + : ''; + return '
' + (en() ? 'Track' : '송장') + '' + + inner + courier + '
'; + } + function row(r, q) { - var ids = []; - if (r.order_id) ids.push('Order ' + hi(r.order_id, q) + ''); - if (r.package_id) ids.push('Pkg ' + hi(r.package_id, q) + ''); - if (r.tracking_id) ids.push((en() ? 'Track ' : '송장 ') + '' + hi(r.tracking_id, q) + ''); var name = r.recipient_name ? hi(r.recipient_name, q) : esc(en() ? '(no recipient name)' : '(받는 사람 정보 없음)'); @@ -306,14 +330,17 @@ if (r.recipient_phone) contact.push(esc(r.recipient_phone)); if (r.recipient_address) contact.push(esc(r.recipient_address)); var done = r.label_attached && r.handed_to_kagayaku; - var batchLine = esc(r.dispatch_date) + ' · ' + esc(r.platform) + ' · ' + esc(r.batch_name || '') - + ' · ' + (en() ? 'Box #' : '박스 #') + esc(r.seq) - + (done ? ' · ' : ''); + // 날짜·쇼핑몰은 굵게. + var batchLine = '' + esc(r.dispatch_date) + ' · ' + esc(r.platform) + ' · ' + + esc(r.batch_name || '') + ' · ' + (en() ? 'Box #' : '박스 #') + esc(r.seq) + + (done ? ' · ' : ''); return '
' - + '
' + + '
' + '
' + name + '
' + (contact.length ? '
' + contact.join(' · ') + '
' : '') - + '
' + ids.join('   ') + '
' + + idLine('Order', r.order_id, q) + + idLine('Pkg', r.package_id, q) + + trackLine(r, q) + '
' + batchLine + '
' + '
' + ''