Files
dbx-corm/templates/index.html
T
king 065e81bf97 feat: v9.0 업그레이드 — CS 작업 탭 개편 + 밀크런/자사몰 행사 모듈
CS 통합 프로그램.ZIP(로컬 개발본 v9.0)의 기능 소스를 반영.
DB 스키마는 기존과 동일해 마이그레이션 없이 그대로 사용한다.

가져온 것
- main.py / cafe24_api.py / templates / static: v9.0 기능 코드
- routers/coupang_milkrun.py, routers/mall_event.py (신규)
- static/js/mall_event.js, static/js/milkrun_gsheet.js (신규)

운영 설정은 기존 것을 유지·재적용
- DB/카페24/네이버 접속정보를 하드코딩 대신 환경변수 기반으로 복원
- SSO(AuthGuardMiddleware, SessionMiddleware), /login, /logout, /health/db 복원
- APP_ROOT_PATH 서브경로 호스팅(root_path 템플릿 변수, app.js fetch 래퍼) 복원
- 구글시트 설정 인메모리 캐시(TTL 10분)와 /api/config/refresh 복원

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 23:56:17 +09:00

4220 lines
149 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<title>[No.1 King] CS 통합 관리앱 (미라클주방)</title>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="{{ root_path }}/static/css/styles.css?v=24"
/>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
<script>
// 서브경로 호스팅 정보 — JS 가 fetch 시 prefix 로 사용한다.
window.APP_BASE_PATH = "{{ root_path }}";
</script>
<style>
.hover-row:hover {
background-color: #a8e0ff !important;
transition: background-color 0.1s;
}
button,
input,
select,
textarea,
table,
th,
td,
span,
div,
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: inherit;
}
/* SortableJS drag styling for set components */
.sortable-ghost {
opacity: 0.4;
background-color: #ebf8ff !important;
border: 1px dashed #3182ce !important;
}
.sortable-chosen {
background-color: #fffaf0 !important;
}
.drag-handle:hover {
color: #2d3748 !important;
}
/* 상품 설정: 엑셀 시트처럼 셀 선택 느낌을 주는 포커스 스타일 */
.product-items-list .pr-item-row input[type="text"]:focus {
outline: 2px solid #3182ce;
outline-offset: -2px;
background: #ebf8ff !important;
}
.product-items-list .pr-item-row:hover {
background: #f7fafc !important;
}
/* 쿠팡 밀크런 분석 로딩 오버레이 */
@keyframes milkrun-spin {
to {
transform: rotate(360deg);
}
}
.milkrun-spinner {
width: 40px;
height: 40px;
border: 4px solid #cbd5e0;
border-top-color: #3182ce;
border-radius: 50%;
animation: milkrun-spin 0.8s linear infinite;
}
</style>
</head>
<body>
<div class="app-container">
<!-- Sidebar Navigation -->
<nav class="sidebar">
<div class="logo">
<h1>No.1 King</h1>
<p>CS 통합 관리</p>
<div
id="app-version-text"
style="color: #a0aec0; font-size: 0.95rem; margin-top: 4px; font-weight: normal"
>
Ver 9.0
</div>
<div style="color: #a0aec0; font-size: 0.75rem; margin-top: 4px; font-weight: normal">
(2026.08.25)
</div>
</div>
<ul class="nav-links">
<li
data-tab="order-tab"
data-order-view="classic"
>
<span class="nav-icon">🎧</span>CS 작업
</li>
<li class="active" data-tab="order-tab" data-order-view="new"><span class="nav-icon"></span>New CS</li>
<li data-tab="manual-tab"><span class="nav-icon">✍️</span>수동발주</li>
<li data-tab="product-tab"><span class="nav-icon">📦</span>상품설정</li>
<li data-tab="auto-order-tab"><span class="nav-icon">🤖</span>자동발주</li>
<li data-tab="code-tab"><span class="nav-icon">🏷️</span>코드표</li>
<li data-tab="return-tab"><span class="nav-icon">↩️</span>반품관리</li>
<li data-tab="mall-event-tab"><span class="nav-icon">🎁</span>자사몰 행사</li>
<li data-tab="milkrun-tab"><span class="nav-icon">🚚</span>밀크런</li>
<li data-tab="gift-tab"><span class="nav-icon">⚙️</span>설정</li>
<li data-tab="version-history-tab"><span class="nav-icon">🚀</span>History</li>
</ul>
</nav>
<!-- Main Content Area -->
<main class="content">
<!-- =========================
INTEGRATED TAB (ORDER + SMS)
========================== -->
<section
id="order-tab"
class="tab-content active"
>
<div class="main-grid">
<div class="order-workspace">
<div class="order-category-panel">
<div class="order-category-heading">
<strong>상품 분류</strong>
<span>제목을 클릭하면 하위 상품이 표시됩니다.</span>
</div>
<div
id="order-group-buttons"
class="order-group-buttons"
></div>
</div>
<div class="order-workspace-body">
<div
id="order-items-container"
class="order-items-inline-host"
>
<!-- Product groups injected via JS -->
</div>
<div class="order-summary-column">
<section class="order-selected-panel" aria-labelledby="order-selected-title">
<div class="order-selected-heading">
<h3 id="order-selected-title">선택 상품</h3>
<span id="order-selected-count">0종</span>
</div>
<div id="order-selected-items" class="order-selected-items">
<p class="order-selected-empty">선택된 상품이 없습니다.</p>
</div>
<div class="order-selected-totals">
<div>
<span>주문 금액</span>
<strong id="order-summary-order-amount">0원</strong>
</div>
<div id="order-summary-adjustments" class="order-summary-adjustments"></div>
<div class="order-summary-final">
<span>입금 금액</span>
<strong id="order-summary-deposit-amount">0원</strong>
</div>
</div>
<button
type="button"
id="btn-sms-preview-open"
class="btn btn-primary order-preview-button"
>문자 미리보기</button>
</section>
<div id="new-cs-options-slot" class="new-cs-options-slot"></div>
</div>
</div>
</div>
<div class="right-col">
<!-- Left Panel inside right-col -->
<div class="right-panel-col1">
<!-- Customer Info -->
<div class="glass-card customer-info">
<h3
style="
border-bottom: 2px solid #3182ce;
padding-bottom: 4px;
margin-bottom: 12px;
width: 100%;
color: #2d3748;
font-size: 1.1rem;
background: transparent;
box-shadow: none;
"
>
📝수동 일반 발주
</h3>
<div class="form-group">
<label>이름</label>
<input
type="text"
id="cust-name"
placeholder="고객명"
/>
</div>
<div class="form-group">
<label>연락처</label>
<input
type="text"
id="cust-phone"
placeholder="010-0000-0000"
/>
</div>
<div class="form-group">
<label>주소</label>
<textarea
id="cust-address"
rows="2"
placeholder="주소 입력"
></textarea>
</div>
<div class="radio-group mt-1">
<label
><input
type="radio"
name="order-type"
value="normal"
checked
/>
일반</label
>
<label
><input
type="radio"
name="order-type"
value="noolak"
/>
누락</label
>
<label
><input
type="radio"
name="order-type"
value="pason"
/>
파손</label
>
<label
><input
type="radio"
name="order-type"
value="bullyang"
/>
불량</label
>
<label
><input
type="radio"
name="order-type"
value="misdelivery"
/>
오배송</label
>
<label
class="checkbox-label no-lid"
style="width: 100%; margin-top: 4px"
><input
type="checkbox"
id="chk-no-lid"
disabled
/>
뚜껑 없이 통만</label
>
</div>
<div class="action-buttons mt-1">
<button
id="btn-submit-normal"
class="btn btn-primary btn-large"
style="background: #3182ce"
>
발주 입력
</button>
<button
id="btn-submit-ellen"
class="btn btn-accent btn-large"
style="background: #ed8936"
>
엘렌 입력
</button>
<button
id="btn-download-sheet"
class="btn btn-secondary btn-large"
style="
grid-column: 1 / -1;
background: #1d6f42;
color: white;
border-color: #175c36;
"
>
엑셀 시트 다운로드
</button>
<div
id="download-progress-container"
style="display: none; grid-column: 1 / -1; margin-top: 4px"
>
<div
style="
font-size: 0.75rem;
margin-bottom: 4px;
display: flex;
justify-content: space-between;
font-weight: 600;
color: #1d6f42;
"
>
<span>엑셀 다운로드 및 시트 비우기 진행 중...</span>
<span id="download-progress-text">0%</span>
</div>
<div
style="
width: 100%;
height: 6px;
background: #e2e8f0;
border-radius: 3px;
overflow: hidden;
"
>
<div
id="download-progress-bar"
style="
width: 0%;
height: 100%;
background: #1d6f42;
transition: width 0.4s ease;
"
></div>
</div>
</div>
</div>
</div>
<div
class="glass-card history-box"
style="
display: flex;
flex-direction: column;
overflow: hidden;
height: 260px;
margin-bottom: 10px;
"
>
<h3
style="
display: flex;
justify-content: space-between;
width: 100%;
margin-bottom: 4px;
font-size: 1.1rem;
align-items: flex-end;
"
>
💬최근 전송 메시지
<span
class="action-text"
id="btn-sms-clear-all"
style="color: red; font-size: 0.75rem"
>전체 삭제</span
>
</h3>
<ul
id="sms-history-list"
style="flex: 1; overflow-y: auto; padding-right: 4px"
></ul>
</div>
<!-- Manual Order History -->
<div
class="glass-card manual-history-box"
style="display: flex; flex-direction: column; overflow: hidden; height: 260px"
>
<h3
style="
border-bottom: 2px solid #3182ce;
padding-bottom: 4px;
margin-bottom: 8px;
width: 100%;
color: #2d3748;
font-size: 1.1rem;
background: transparent;
box-shadow: none;
"
>
📝오늘 수동발주 내역
</h3>
<div
style="
margin-bottom: 8px;
display: flex;
justify-content: space-between;
align-items: flex-end;
"
>
<div
style="
font-size: 0.95rem;
color: #4a5568;
border-bottom: 2px solid #ed8936;
padding-bottom: 2px;
display: inline-block;
"
>
<span
id="manual-total-count"
style="color: #ed8936; font-weight: bold"
>0</span
>건 /
<span
id="manual-total-amount"
style="color: #ed8936; font-weight: bold"
>0</span
>
</div>
<button
class="btn btn-secondary btn-sm"
id="btn-copy-manual-total"
style="font-size: 0.75rem; padding: 2px 6px"
>
복사
</button>
</div>
<ul
id="manual-history-list"
style="flex: 1; overflow-y: auto; padding-right: 4px"
></ul>
</div>
</div>
<div class="right-panel-col2" id="classic-options-slot">
<div
id="sms-preview-modal"
class="sms-preview-modal"
aria-hidden="true"
>
<div
class="glass-card sms-preview-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="sms-preview-title"
>
<div class="sms-preview-heading">
<h3 id="sms-preview-title">문자 미리보기</h3>
<button
type="button"
id="btn-sms-preview-close"
class="btn btn-secondary"
>닫기</button>
</div>
<div
id="sms-preview"
style="
font-size: 0.75rem;
font-family: &quot;Malgun Gothic&quot;, sans-serif;
overflow-y: auto;
background: #fff;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
white-space: pre-wrap;
"
></div>
</div>
</div>
<!-- SMS Options Group -->
<div class="glass-card sms-options">
<h3
style="
border-bottom: 2px solid #3182ce;
padding-bottom: 4px;
margin-bottom: 12px;
width: 100%;
color: #2d3748;
font-size: 1.1rem;
background: transparent;
box-shadow: none;
"
>
📋알림 문자 계산 및 복사
</h3>
<div
class="chk-grid"
style="
grid-template-columns: max-content max-content;
justify-content: start;
gap: 4px 15px;
align-items: center;
"
>
<label
><input
type="checkbox"
id="sms-discount"
/>
5% 할인</label
>
<label
><input
type="checkbox"
id="sms-june-promo"
/>
금액별 추가상품</label
>
<label
><input
type="checkbox"
id="sms-ship-extra"
/>
<span id="lbl-ship-extra">추가배송비 3,000원</span></label
>
<label
><input
type="checkbox"
id="sms-ship-free"
/>
무료배송</label
>
<label
><input
type="checkbox"
id="sms-coupon"
/>
6종 할인 쿠폰 적용</label
>
<label style="display: flex; align-items: center"
>적립금
<input
type="text"
id="sms-point-deduction"
style="width: 70px; margin: 0 5px; text-align: right; font-size: 0.85rem"
placeholder="0"
/>
차감</label
>
</div>
<div
class="action-buttons horizontal mt-1"
style="margin-top: 8px; display: flex; gap: 8px"
>
<button
id="btn-sms-calc"
class="btn btn-primary block"
style="flex: 1"
>
문자 내용 복사
</button>
<button
id="btn-reset"
class="btn btn-danger"
style="
flex: 0 0 auto;
padding-left: 5px;
padding-right: 5px;
background: #e53e3e;
white-space: nowrap;
"
>
초기화
</button>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- =========================
AUTO ORDER TAB
========================== -->
<section
id="auto-order-tab"
class="tab-content flex-layout"
style="padding: 20px; overflow-y: hidden; height: 100%; flex-direction: column"
>
<header style="margin-bottom: 1.5rem; text-align: center; flex-shrink: 0">
<h1 style="color: #fff; margin-bottom: 5px">🔥 통합 자동발주 시스템</h1>
<p style="color: #e2e8f0; font-size: 1rem; margin: 0">
카페24 및 스마트스토어의 주문 내역을 한 곳에서 관리하세요.
</p>
</header>
<div
style="
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
flex: 1;
overflow: hidden;
"
>
<!-- 좌측: 카페24 패널 -->
<div
style="
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
background: rgba(30, 30, 30, 0.4);
padding: 15px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
"
>
<h2
style="
color: #fff;
text-align: center;
margin-bottom: 20px;
border-bottom: 2px solid #555;
padding-bottom: 10px;
"
>
🛒 카페24 (자사몰)
</h2>
<div
class="glass-card download-section"
style="
margin-bottom: 1rem;
padding: 20px;
background: rgba(30, 30, 30, 0.8) !important;
"
>
<!-- 카페24 전용 기능(oauth 로그인 등 필요시 추가 가능) -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #a0aec0;
padding-bottom: 10px;
margin-bottom: 15px;
"
>
<h2 style="font-size: 1.1rem; margin: 0; color: #fff; white-space: nowrap">
1. 신규 주문 내역 다운로드
</h2>
<button
id="cafe24AuthBtn"
class="btn btn-secondary"
style="
padding: 2px 6px;
font-size: 0.7rem;
background-color: #4a5568;
color: white;
border-radius: 4px;
border: none;
cursor: pointer;
white-space: nowrap;
margin-left: 5px;
"
>
연동 (최초 1회)
</button>
</div>
<p style="margin-bottom: 15px; color: #cbd5e0">
배송준비중(N20) 상태인 자사몰 주문 내역을 다운로드합니다.
</p>
<!-- 스마트스토어 토글 스위치 영역과 높이를 일치시키기 위한 투명 스페이서 -->
<div style="margin-bottom: 1rem; height: 26px; display: flex"></div>
<button
id="cafe24DownloadBtn"
class="btn btn-primary btn-large"
style="
width: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background-color: #2d3748;
"
>
<span class="icon">⬇️</span> 카페24 주문 내역 다운로드 (Excel)
</button>
<div
id="cafe24ProgressWrapper"
class="hidden"
style="margin-top: 15px"
>
<div style="display: flex; justify-content: space-between; margin-bottom: 5px">
<span
id="cafe24ProgressText"
style="color: #cbd5e0; font-size: 0.9rem"
>수집 준비 중...</span
>
<span
id="cafe24ProgressPercent"
style="color: #fff; font-weight: bold; font-size: 0.9rem"
>0%</span
>
</div>
<div
style="
width: 100%;
height: 10px;
background-color: #4a5568;
border-radius: 5px;
overflow: hidden;
"
>
<div
id="cafe24ProgressBar"
style="
width: 0%;
height: 100%;
background-color: #4299e1;
transition: width 0.3s ease;
"
></div>
</div>
</div>
</div>
<div style="text-align: center; color: #fff; font-size: 2rem; margin: 0.5rem 0">
</div>
<div
class="glass-card upload-section"
style="
margin-top: 0.5rem;
padding: 20px;
background: rgba(30, 30, 30, 0.8) !important;
"
>
<div
style="
border-bottom: 2px solid #a0aec0;
padding-bottom: 10px;
margin-bottom: 15px;
"
>
<h2 style="font-size: 1.2rem; margin: 0; color: #fff">2. 송장 일괄 등록</h2>
</div>
<p style="margin-bottom: 15px; color: #cbd5e0">
송장번호가 입력된 엑셀 파일을 업로드합니다.
</p>
<form id="cafe24UploadForm">
<div style="margin-bottom: 15px">
<label
for="cafe24DeliveryCompany"
style="display: block; font-weight: bold; margin-bottom: 5px; color: #fff"
>택배사 선택</label
>
<select
id="cafe24DeliveryCompany"
name="deliveryCompanyCode"
style="
width: 100%;
padding: 10px;
border-radius: 4px;
border: 1px solid #718096;
background: #2d3748;
color: white;
"
>
<option
value="0004"
selected
>
CJ대한통운
</option>
<option value="0005">한진택배</option>
<option value="0002">우체국택배</option>
<option value="0001">롯데택배</option>
<option value="0010">로젠택배</option>
<option value="0023">경동택배</option>
<option value="0003">대신택배</option>
<option value="0039">우체국EMS</option>
</select>
</div>
<div
class="file-drop-area"
id="cafe24FileDropArea"
style="background: rgba(255, 255, 255, 0.05); border-color: #718096"
>
<span
class="file-msg"
id="cafe24FileMsg"
style="color: #cbd5e0"
>엑셀 파일을 이곳에 드래그하거나 클릭하여 업로드하세요. (.xls, .xlsx)</span
>
<input
type="file"
id="cafe24InvoiceFile"
name="file"
accept=".xls,.xlsx"
required
style="display: none"
/>
</div>
<button
type="submit"
id="cafe24UploadBtn"
class="btn btn-secondary btn-large"
style="
width: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background-color: #4a5568;
margin-top: 15px;
color: white;
"
disabled
>
<span class="icon">🚀</span> 송장 일괄 발송처리
</button>
<div
id="cafe24UploadSpinner"
class="spinner hidden"
style="border-color: #cbd5e0; border-top-color: transparent"
></div>
</form>
</div>
<div
id="cafe24ResultBox"
class="result-box hidden"
style="margin-top: 15px; padding: 15px; border-radius: 4px"
>
<h3
id="cafe24ResultTitle"
style="margin-top: 0; color: #fff"
>
결과
</h3>
<p
id="cafe24ResultText"
style="margin-bottom: 0; color: #fff"
></p>
</div>
</div>
<!-- 우측: 스마트스토어 패널 -->
<div
style="
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
background: rgba(3, 199, 90, 0.1);
padding: 15px;
border-radius: 12px;
border: 1px solid rgba(3, 199, 90, 0.3);
"
>
<h2
style="
color: #fff;
text-align: center;
margin-bottom: 20px;
border-bottom: 2px solid #03c75a;
padding-bottom: 10px;
"
>
🟩 스마트스토어
</h2>
<div
class="glass-card download-section"
style="margin-bottom: 1rem; padding: 20px"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #3182ce;
padding-bottom: 10px;
margin-bottom: 15px;
"
>
<h2 style="font-size: 1.2rem; margin: 0; color: #000">
1. 신규 주문 내역 다운로드
</h2>
<div
style="
background-color: #e53e3e;
color: white;
padding: 4px 10px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: bold;
"
>
발주확인 요망
</div>
</div>
<p style="margin-bottom: 15px; color: #4a5568">
결제완료 상태인 주문 내역을 다운로드합니다.
</p>
<div
style="
margin-bottom: 1rem;
display: flex;
align-items: center;
justify-content: flex-end;
"
>
<label
for="confirmToggle"
style="margin-right: 0.5rem; font-weight: 500; font-size: 0.95rem; color: #555"
>다운로드 시 발주확인(배송준비중) 처리</label
>
<div class="toggle-switch">
<input
type="checkbox"
id="confirmToggle"
/>
<label
for="confirmToggle"
class="switch-label"
></label>
</div>
</div>
<button
id="downloadBtn"
class="btn btn-primary btn-large"
style="
width: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background-color: #03c75a;
"
>
<span class="icon">⬇️</span> 스마트스토어 주문 내역 다운로드 (Excel)
</button>
<div
id="smartstoreProgressWrapper"
class="hidden"
style="margin-top: 15px"
>
<div style="display: flex; justify-content: space-between; margin-bottom: 5px">
<span
id="smartstoreProgressText"
style="color: #4a5568; font-size: 0.9rem"
>수집 준비 중...</span
>
<span
id="smartstoreProgressPercent"
style="color: #000; font-weight: bold; font-size: 0.9rem"
>0%</span
>
</div>
<div
style="
width: 100%;
height: 10px;
background-color: #cbd5e0;
border-radius: 5px;
overflow: hidden;
"
>
<div
id="smartstoreProgressBar"
style="
width: 0%;
height: 100%;
background-color: #03c75a;
transition: width 0.3s ease;
"
></div>
</div>
</div>
</div>
<div style="text-align: center; color: #fff; font-size: 2rem; margin: 0.5rem 0">
</div>
<div
class="glass-card upload-section"
style="margin-top: 0.5rem; padding: 20px"
>
<div
style="
border-bottom: 2px solid #3182ce;
padding-bottom: 10px;
margin-bottom: 15px;
"
>
<h2 style="font-size: 1.2rem; margin: 0; color: #000">2. 송장 일괄 등록</h2>
</div>
<p style="margin-bottom: 15px; color: #4a5568">
송장번호가 입력된 엑셀 파일을 업로드합니다.
</p>
<form id="uploadForm">
<div style="margin-bottom: 15px">
<label
for="deliveryCompany"
style="display: block; font-weight: bold; margin-bottom: 5px; color: #000"
>택배사 선택</label
>
<select
id="deliveryCompany"
name="deliveryCompanyCode"
style="
width: 100%;
padding: 10px;
border-radius: 4px;
border: 1px solid #cbd5e0;
"
>
<option
value="CJGLS"
selected
>
CJ대한통운
</option>
<option value="HANJIN">한진택배</option>
<option value="LOTTE">롯데택배</option>
<option value="EPOST">우체국택배</option>
<option value="KGB">로젠택배</option>
<option value="CVSNET">편의점택배</option>
<option value="KDEX">경동택배</option>
<option value="DAESIN">대신택배</option>
<option value="ILYANGLOGIS">일양로지스</option>
</select>
</div>
<div
class="file-drop-area"
id="fileDropArea"
>
<span class="file-msg"
>엑셀 파일을 이곳에 드래그하거나 클릭하여 업로드하세요. (.xls, .xlsx)</span
>
<input
type="file"
id="invoiceFile"
name="file"
accept=".xls,.xlsx"
required
style="display: none"
/>
</div>
<button
type="submit"
id="uploadBtn"
class="btn btn-secondary btn-large"
style="
width: 100%;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background-color: #3182ce;
margin-top: 15px;
color: white;
"
disabled
>
<span class="icon">🚀</span> 송장 일괄 발송처리
</button>
<div
id="uploadSpinner"
class="spinner hidden"
></div>
</form>
</div>
<div
id="resultBox"
class="result-box hidden"
style="margin-top: 15px; padding: 15px; border-radius: 4px"
>
<h3
id="resultTitle"
style="margin-top: 0"
>
결과
</h3>
<p
id="resultText"
style="margin-bottom: 0"
></p>
</div>
</div>
<!-- 3번째 패널 (준비 중) -->
<div
style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.02);
border-radius: 12px;
border: 2px dashed rgba(255, 255, 255, 0.15);
"
>
<span
style="
font-size: 18rem;
color: rgba(255, 255, 255, 0.2);
font-weight: bold;
user-select: none;
cursor: default;
line-height: 1;
"
>?</span
>
<span
style="
color: rgba(255, 255, 255, 0.5);
font-size: 1.5rem;
font-weight: 600;
margin-top: 20px;
"
>준비 중...</span
>
</div>
<!-- 4번째 패널 (준비 중) -->
<div
style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.02);
border-radius: 12px;
border: 2px dashed rgba(255, 255, 255, 0.15);
"
>
<span
style="
font-size: 18rem;
color: rgba(255, 255, 255, 0.2);
font-weight: bold;
user-select: none;
cursor: default;
line-height: 1;
"
>?</span
>
<span
style="
color: rgba(255, 255, 255, 0.5);
font-size: 1.5rem;
font-weight: 600;
margin-top: 20px;
"
>준비 중...</span
>
</div>
</div>
</section>
<!-- =========================
MANUAL ORDER TAB
========================== -->
<section
id="manual-tab"
class="tab-content"
style="padding: 0"
>
<div style="padding: 10px 10px 0 10px; display: flex; justify-content: flex-end">
<a
href="https://docs.google.com/spreadsheets/d/1QxFtjDurPPZd8NmtXBy4XEUIzkf93aXD5Mlx5kB33xw/edit?gid=0#gid=0"
target="_blank"
class="btn btn-secondary"
style="
font-size: 0.8rem;
background: #38a169;
color: white;
text-decoration: none;
padding: 6px 12px;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
"
>
새 창에서 구글 시트 직접 열기 (로그인 오류 시 클릭)
</a>
</div>
<div
style="flex: 1; padding: 10px; padding-bottom: 0; position: relative"
id="manual-iframe-container"
>
<div
id="sheet-loader"
class="sheet-loader-overlay"
style="display: none"
>
<div class="spinner"></div>
<p style="margin-top: 15px; font-weight: 600; color: #2b6cb0; font-size: 1.1rem">
구글 시트 아랫줄에 기록 중입니다...
</p>
</div>
<iframe
src="https://docs.google.com/spreadsheets/d/1QxFtjDurPPZd8NmtXBy4XEUIzkf93aXD5Mlx5kB33xw/edit?gid=0#gid=0"
width="100%"
height="100%"
style="border: none; border-radius: 8px; box-shadow: var(--card-shadow)"
></iframe>
</div>
</section>
<!-- =========================
GIFT SETTINGS TAB
========================== -->
<section
id="gift-tab"
class="tab-content"
style="flex-wrap: wrap; flex-direction: row; padding: 15px; gap: 20px; position: relative"
>
<div
class="left-settings"
style="flex: 1; min-width: 400px; display: flex; flex-direction: column; height: 100%"
>
<header>
<h1 style="color: #fff">금액별 추가상품 설정</h1>
</header>
<div
class="gift-settings-container scroll-area"
id="gift-rules-container"
style="flex: 1; margin-top: 10px; gap: 10px"
>
<!-- Rule cards injected via JS -->
</div>
</div>
<div
class="right-settings"
style="display: flex; flex-direction: column; position: relative; height: 100%"
>
<header>
<h1 style="color: #fff">문자 메시지 설정</h1>
</header>
<div
style="
background: rgba(255, 255, 255, 0.85);
border-radius: 8px;
padding: 15px;
width: 370px;
height: 490px;
max-width: 370px;
max-height: 490px;
box-sizing: border-box;
flex-shrink: 0;
margin-top: 10px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
gap: 10px;
"
>
<h3 style="color: #000; border-bottom: none; margin-bottom: 0">머리말</h3>
<textarea
id="sms-header-text"
style="
width: 100%;
height: 150px;
border: 2px solid #e2e8f0;
border-radius: 4px;
resize: none;
padding: 10px;
font-size: 0.8rem;
"
></textarea>
<h3 style="color: #000; border-bottom: none; margin-bottom: 0">
꼬리말(입금 금액은 {최종금액} 으로 입력)
</h3>
<textarea
id="sms-footer-text"
style="
width: 100%;
flex: 1;
border: 2px solid #e2e8f0;
border-radius: 4px;
resize: none;
padding: 10px;
font-size: 0.8rem;
"
></textarea>
</div>
</div>
<div
class="third-settings"
style="display: flex; flex-direction: column; position: relative; height: 100%"
>
<header>
<h1 style="color: #fff">화면 폰트 및 배송비 설정</h1>
</header>
<div
style="
background: rgba(255, 255, 255, 0.85);
border-radius: 8px;
padding: 15px;
width: 380px;
box-sizing: border-box;
flex-shrink: 0;
margin-top: 10px;
box-shadow: var(--card-shadow);
display: flex;
flex-direction: column;
gap: 10px;
"
>
<h3 style="color: #000; border-bottom: none; margin-bottom: 0">폰트 선택</h3>
<div style="display: flex; gap: 5px">
<select
id="app-font-select"
style="
width: 300px;
max-width: 300px;
border: 2px solid #e2e8f0;
border-radius: 4px;
padding: 6px;
font-size: 0.85rem;
text-overflow: ellipsis;
white-space: nowrap;
"
>
<option value="">로딩 중...</option>
</select>
<button
id="btn-font-default"
class="btn btn-secondary"
style="white-space: nowrap; padding: 6px 10px; border-radius: 4px"
>
기본값
</button>
</div>
<h3 style="color: #000; border-bottom: none; margin-top: 15px; margin-bottom: 0">
배송비 설정
</h3>
<div
style="
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 10px;
font-size: 0.95rem;
"
>
<label
style="
display: flex;
justify-content: space-between;
align-items: center;
width: 230px;
"
>
기본 배송비:
<div>
<input
type="text"
id="setting-ship-base"
style="width: 100px; text-align: right; font-size: 0.85rem; padding: 4px"
placeholder="3,500"
/>
</div>
</label>
<label
style="
display: flex;
justify-content: space-between;
align-items: center;
width: 230px;
"
>
추가 배송비:
<div>
<input
type="text"
id="setting-ship-extra"
style="width: 100px; text-align: right; font-size: 0.85rem; padding: 4px"
placeholder="3,000"
/>
</div>
</label>
</div>
</div>
</div>
<div
class="settings-action-container"
style="position: absolute; bottom: 20px; right: 20px; display: flex; gap: 10px"
>
<button
id="btn-gift-save"
class="btn btn-primary"
style="
padding: 10px 20px;
font-size: 0.95rem;
font-weight: bold;
background: #3182ce;
transition: background 0.3s ease;
"
>
설정 저장
</button>
</div>
</section>
<!-- =========================
PRODUCT SETTINGS TAB
========================== -->
<section
id="product-tab"
class="tab-content flex-layout"
style="padding: 15px; height: 100%; position: relative"
>
<header>
<h1 style="color: #fff">상품 설정</h1>
</header>
<div
id="product-groups-container"
style="
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
margin-top: 10px;
padding-bottom: 60px;
"
>
<!-- Groups injected via JS -->
</div>
<div
style="
position: absolute;
bottom: 20px;
right: 20px;
z-index: 10;
display: flex;
gap: 10px;
"
>
<button
id="btn-product-save"
class="btn btn-primary"
style="
padding: 10px 20px;
font-size: 0.95rem;
font-weight: bold;
background: #3182ce;
transition: background 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
"
>
상품 설정 저장
</button>
</div>
</section>
<!-- =========================
CODE SETTINGS TAB
========================== -->
<section
id="code-tab"
class="tab-content flex-layout"
style="padding: 15px; height: 100%; position: relative"
>
<header>
<h1 style="color: #fff">코드표 관리</h1>
</header>
<div
class="code-split-container"
style="display: flex; gap: 20px; flex: 1; overflow: hidden; margin-top: 10px"
>
<!-- 단품 관리 영역 -->
<div
class="glass-card"
style="
flex: 0 0 560px;
width: 560px;
max-width: 560px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0; white-space: nowrap">
단품 코드
</h2>
<div style="display: flex; align-items: center; gap: 5px; flex: 1; margin: 0 10px">
<input
type="text"
id="single-search-input"
placeholder="단품 이름 검색"
autocomplete="off"
style="
flex: 1;
min-width: 0;
padding: 4px 8px;
font-size: 0.85rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
background: #fff;
color: #2d3748;
"
/>
<button
id="btn-single-search-clear"
class="btn btn-sm"
type="button"
title="검색 초기화"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
white-space: nowrap;
"
>
초기화
</button>
</div>
<button
id="btn-add-single"
class="btn btn-primary btn-sm"
style="background: #3182ce; padding: 5px 10px; white-space: nowrap"
>
+ 새 단품 추가
</button>
</div>
<div
style="
flex: 1;
overflow-y: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
"
>
<table
style="
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 0.9rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #ebf8ff;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th
class="th-sortable"
data-list="single"
data-key="item_code"
style="
padding: 10px;
font-weight: 600;
cursor: pointer;
width: 100px;
white-space: nowrap;
"
>
아이템코드
<span
class="sort-icon"
style="color: #3182ce; font-size: 0.8rem"
></span
>
</th>
<th
class="th-sortable"
data-list="single"
data-key="sabangnet_code"
style="
padding: 10px;
font-weight: 600;
cursor: pointer;
width: 105px;
white-space: nowrap;
"
>
사방넷 코드
<span
class="sort-icon"
style="color: #e2e8f0; font-size: 0.8rem"
></span
>
</th>
<th
class="th-sortable"
data-list="single"
data-key="name"
style="
padding: 10px;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
"
>
이름
<span
class="sort-icon"
style="color: #e2e8f0; font-size: 0.8rem"
></span
>
</th>
<th style="padding: 10px; text-align: right; width: 60px">관리</th>
</tr>
</thead>
<tbody id="single-items-tbody"></tbody>
</table>
</div>
</div>
<!-- 세트 관리 영역 -->
<div
class="glass-card"
style="
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0; white-space: nowrap">
세트 코드
</h2>
<div
style="
display: flex;
align-items: center;
gap: 5px;
flex: 0 0 320px;
margin: 0 10px;
"
>
<input
type="text"
id="set-search-input"
placeholder="세트 이름 검색"
autocomplete="off"
style="
flex: 1;
min-width: 0;
padding: 4px 8px;
font-size: 0.85rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
background: #fff;
color: #2d3748;
"
/>
<button
id="btn-set-search-clear"
class="btn btn-sm"
type="button"
title="검색 초기화"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
white-space: nowrap;
"
>
초기화
</button>
</div>
<button
id="btn-add-set"
class="btn btn-accent btn-sm"
style="
background: #ed8936;
padding: 5px 10px;
white-space: nowrap;
margin-left: auto;
"
>
+ 새 세트 추가
</button>
</div>
<div
style="
flex: 1;
overflow-y: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
"
>
<table
style="
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 0.9rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #fffaf0;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th
class="th-sortable"
data-list="set"
data-key="item_code"
style="
padding: 10px;
font-weight: 600;
cursor: pointer;
width: 100px;
white-space: nowrap;
"
>
아이템코드
<span
class="sort-icon"
style="color: #3182ce; font-size: 0.8rem"
></span
>
</th>
<th
class="th-sortable"
data-list="set"
data-key="name"
style="
padding: 10px;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
"
>
세트 이름
<span
class="sort-icon"
style="color: #e2e8f0; font-size: 0.8rem"
></span
>
</th>
<th style="padding: 10px; font-weight: 600">구성 단품 목록</th>
<th style="padding: 10px; text-align: right; width: 60px">관리</th>
</tr>
</thead>
<tbody id="set-items-tbody"></tbody>
</table>
</div>
</div>
</div>
</section>
<!-- =========================
MALL EVENT TAB (자사몰 행사)
카페24 발주주문서를 업로드해 행사 조건을 적용하고 가공된 발주 파일을 내려받는 공간.
기능이 늘어나면 왼쪽 '기능' 목록에 항목을 추가하고 패널을 하나 더 만든다.
========================== -->
<section
id="mall-event-tab"
class="tab-content flex-layout"
style="padding: 15px; height: 100%; position: relative"
>
<header>
<h1 style="color: #fff">자사몰 행사 (카페24 발주서 가공)</h1>
</header>
<div
id="me-loading-overlay"
style="
display: none;
position: absolute;
inset: 0;
z-index: 50;
background: rgba(255, 255, 255, 0.7);
align-items: center;
justify-content: center;
flex-direction: column;
gap: 12px;
"
>
<div class="milkrun-spinner"></div>
<div
id="me-loading-text"
style="font-size: 1rem; font-weight: 600; color: #2d3748"
>
처리 중...
</div>
</div>
<div style="display: flex; gap: 20px; flex: 1; overflow: hidden; margin-top: 10px">
<!-- 기능 목록 -->
<div
class="glass-card"
style="
flex: 0 0 180px;
width: 180px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<h2 style="font-size: 1.05rem; color: #000000; margin: 0 0 10px 0">기능</h2>
<div
id="me-feature-list"
style="display: flex; flex-direction: column; gap: 6px; overflow-y: auto"
>
<button
type="button"
class="me-feature-btn active"
data-feature="first-come"
style="
text-align: left;
padding: 8px 10px;
border: 1px solid #bee3f8;
background: #ebf8ff;
color: #2b6cb0;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
font-weight: 600;
"
>
선착순 사은품 추가
</button>
<button
type="button"
class="me-feature-btn"
data-feature="event-extract"
style="
text-align: left;
padding: 8px 10px;
border: 1px solid #e2e8f0;
background: #fff;
color: #4a5568;
border-radius: 4px;
cursor: pointer;
font-size: 0.85rem;
font-weight: 600;
"
>
행사주문 추출(아롱)
</button>
</div>
<div
style="
margin-top: auto;
font-size: 0.7rem;
color: #a0aec0;
line-height: 1.4;
padding-top: 10px;
"
>
기능은 계속 추가됩니다.
</div>
</div>
<!-- 기능 패널: 선착순 사은품 추가 -->
<div
id="me-panel-first-come"
class="me-feature-panel"
style="display: flex; gap: 20px; flex: 1; overflow: hidden"
>
<!-- 1. 파일 업로드 -->
<div
class="glass-card"
style="
flex: 0 0 320px;
width: 320px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0">1. 발주서 업로드</h2>
<button
id="btn-me-reset"
class="btn btn-sm"
type="button"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
"
>
초기화
</button>
</div>
<div
id="me-dropzone"
style="
border: 2px dashed #cbd5e0;
border-radius: 6px;
background: #f7fafc;
padding: 20px 12px;
text-align: center;
cursor: pointer;
transition:
background 0.2s,
border-color 0.2s;
"
>
<div style="font-size: 2rem; line-height: 1">📥</div>
<div
style="margin-top: 8px; font-size: 0.88rem; color: #2d3748; font-weight: 600"
>
엑셀 파일을 여기로 끌어다 놓으세요
</div>
<div style="margin-top: 4px; font-size: 0.75rem; color: #718096">
또는 아래 버튼으로 직접 선택 (.xlsx)
</div>
<button
id="btn-me-pick-file"
class="btn btn-primary btn-sm"
type="button"
style="margin-top: 10px; background: #3182ce; padding: 6px 14px"
>
파일 선택
</button>
<input
type="file"
id="me-file-input"
accept=".xlsx,.xlsm"
style="display: none"
/>
</div>
<div
id="me-file-info"
style="
display: none;
margin-top: 12px;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: #fff;
padding: 10px;
font-size: 0.82rem;
color: #2d3748;
line-height: 1.6;
"
></div>
<div
id="me-file-error"
style="
display: none;
margin-top: 12px;
background: #fff5f5;
border: 1px solid #feb2b2;
color: #c53030;
border-radius: 4px;
padding: 8px 10px;
font-size: 0.82rem;
"
></div>
<div
style="
margin-top: auto;
padding-top: 12px;
font-size: 0.72rem;
color: #718096;
line-height: 1.5;
"
>
카페24에서 받은 발주주문서를 그대로 올리면 됩니다. Q열(주문목록)의 첫 "/" 앞부분을
기준으로 상품 목록을 만듭니다.
</div>
</div>
<!-- 2. 사은품이 지급되는 주문 -->
<div
class="glass-card"
style="
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0; white-space: nowrap">
2. 사은품이 지급되는 주문
</h2>
<div
style="
display: flex;
align-items: center;
gap: 5px;
margin-left: 10px;
flex: 1;
justify-content: flex-end;
"
>
<input
type="text"
id="me-order-search"
placeholder="상품 이름 검색"
autocomplete="off"
style="
flex: 0 1 200px;
min-width: 0;
padding: 4px 8px;
font-size: 0.85rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
background: #fff;
color: #2d3748;
"
/>
<button
id="btn-me-select-all"
class="btn btn-sm"
type="button"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
white-space: nowrap;
"
>
전체 선택
</button>
<button
id="btn-me-select-none"
class="btn btn-sm"
type="button"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
white-space: nowrap;
"
>
해제
</button>
</div>
</div>
<div
id="me-order-list"
style="
flex: 1;
overflow-y: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
padding: 4px;
"
>
<div
style="padding: 20px; text-align: center; color: #a0aec0; font-size: 0.85rem"
>
발주서를 업로드하면 주문 목록이 표시됩니다.
</div>
</div>
<div
id="me-order-selected-info"
style="margin-top: 8px; font-size: 0.8rem; color: #4a5568"
></div>
</div>
<!-- 3. 사은품 조건 / 결과 -->
<div
class="glass-card"
style="
flex: 0 0 400px;
width: 400px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0 0 10px 0">
3. 사은품 조건
</h2>
<label style="font-size: 0.82rem; color: #4a5568; font-weight: 600"
>선착순 인원</label
>
<div style="display: flex; gap: 5px; align-items: center; margin: 4px 0 10px 0">
<button
type="button"
class="me-limit-preset btn btn-sm"
data-value="10"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
"
>
10
</button>
<button
type="button"
class="me-limit-preset btn btn-sm"
data-value="30"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
"
>
30
</button>
<button
type="button"
class="me-limit-preset btn btn-sm"
data-value="50"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
"
>
50
</button>
<button
type="button"
class="me-limit-preset btn btn-sm"
data-value="100"
style="
padding: 4px 8px;
font-size: 0.8rem;
background: #e2e8f0;
color: #4a5568;
box-shadow: none;
"
>
100
</button>
<input
type="number"
id="me-limit"
min="1"
step="1"
value="30"
style="
flex: 1;
min-width: 0;
padding: 5px 8px;
font-size: 0.9rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
text-align: right;
"
/>
<span style="font-size: 0.85rem; color: #4a5568"></span>
</div>
<label style="font-size: 0.82rem; color: #4a5568; font-weight: 600"
>사은품 (세트 코드)</label
>
<select
id="me-gift-select"
style="
margin: 4px 0 2px 0;
padding: 6px 8px;
font-size: 0.85rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
background: #fff;
color: #2d3748;
"
>
<option value="">코드표에서 세트를 불러오는 중...</option>
</select>
<div style="font-size: 0.72rem; color: #a0aec0; margin-bottom: 10px">
코드표 세트 중 이름에 "사은품"이 들어간 것만 표시됩니다.
</div>
<label style="font-size: 0.82rem; color: #4a5568; font-weight: 600"
>사은품 수량</label
>
<input
type="number"
id="me-gift-qty"
min="1"
step="1"
value="1"
style="
margin: 4px 0 12px 0;
padding: 5px 8px;
font-size: 0.9rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
text-align: right;
"
/>
<button
id="btn-me-apply"
class="btn btn-primary"
type="button"
style="background: #3182ce; padding: 9px 12px; font-weight: bold"
>
사은품 적용 결과 보기
</button>
<div
id="me-warning-box"
style="
display: none;
margin-top: 10px;
background: #fffaf0;
border: 1px solid #fbd38d;
color: #975a16;
border-radius: 4px;
padding: 8px 10px;
font-size: 0.8rem;
line-height: 1.5;
"
></div>
<div
id="me-result-info"
style="margin-top: 10px; font-size: 0.82rem; color: #2d3748; font-weight: 600"
></div>
<div
style="
flex: 1;
overflow-y: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
margin-top: 6px;
min-height: 80px;
"
>
<table
style="
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 0.76rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #fffaf0;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th style="padding: 6px 8px; font-weight: 600; white-space: nowrap">#</th>
<th style="padding: 6px 8px; font-weight: 600; white-space: nowrap">
주문번호
</th>
<th style="padding: 6px 8px; font-weight: 600; white-space: nowrap">
주문날짜
</th>
<th style="padding: 6px 8px; font-weight: 600; white-space: nowrap">
새 C열
</th>
</tr>
</thead>
<tbody id="me-result-tbody"></tbody>
</table>
</div>
<div style="display: flex; gap: 8px; margin-top: 10px">
<button
id="btn-me-download-full"
class="btn btn-secondary btn-sm"
type="button"
disabled
style="
flex: 1;
background: #1d6f42;
color: white;
border-color: #175c36;
padding: 8px 6px;
line-height: 1.3;
opacity: 0.5;
"
>
전체 발주 파일<br />다운로드
</button>
<button
id="btn-me-download-gift"
class="btn btn-secondary btn-sm"
type="button"
disabled
style="
flex: 1;
background: #b7791f;
color: white;
border-color: #975a16;
padding: 8px 6px;
line-height: 1.3;
opacity: 0.5;
"
>
사은품 대상 주문만<br />다운로드
</button>
</div>
</div>
</div>
<!-- 기능 패널: 행사 주문 추출 -->
<div
id="me-panel-event-extract"
class="me-feature-panel"
style="display: none; gap: 20px; flex: 1; overflow: hidden"
>
<!-- 1. CSV 업로드 -->
<div
class="glass-card"
style="flex: 0 0 320px; width: 320px; display: flex; flex-direction: column; overflow: hidden; padding: 15px;"
>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h2 style="font-size: 1.2rem; color: #000000; margin: 0">1. 주문 CSV 업로드</h2>
<button
id="btn-ee-reset"
class="btn btn-sm"
type="button"
style="padding: 4px 8px; font-size: 0.8rem; background: #e2e8f0; color: #4a5568; box-shadow: none;"
>
초기화
</button>
</div>
<div
id="ee-dropzone"
style="border: 2px dashed #cbd5e0; border-radius: 6px; background: #f7fafc; padding: 20px 12px; text-align: center; cursor: pointer; transition: background 0.2s, border-color 0.2s;"
>
<div style="font-size: 2rem; line-height: 1">📄</div>
<div style="margin-top: 8px; font-size: 0.88rem; color: #2d3748; font-weight: 600;">
CSV 파일을 여기로 끌어다 놓으세요
</div>
<div style="margin-top: 4px; font-size: 0.75rem; color: #718096">
또는 아래 버튼으로 직접 선택 (.csv)
</div>
<button
id="btn-ee-pick-file"
class="btn btn-primary btn-sm"
type="button"
style="margin-top: 10px; background: #3182ce; padding: 6px 14px"
>
파일 선택
</button>
<input type="file" id="ee-file-input" accept=".csv" style="display: none" />
</div>
<div
id="ee-file-info"
style="display: none; margin-top: 12px; border: 1px solid #e2e8f0; border-radius: 4px; background: #fff; padding: 10px; font-size: 0.82rem; color: #2d3748; line-height: 1.6;"
></div>
<div
id="ee-file-error"
style="display: none; margin-top: 12px; background: #fff5f5; border: 1px solid #feb2b2; color: #c53030; border-radius: 4px; padding: 8px 10px; font-size: 0.82rem;"
></div>
<div style="margin-top: auto; padding-top: 12px; font-size: 0.72rem; color: #718096; line-height: 1.5;">
카페24에서 받은 주문 CSV를 그대로 올리면 됩니다. K열(주문상품명)의 첫 " -" 앞부분을
기준으로 상품 목록을 만듭니다.
</div>
</div>
<!-- 2. 추출할 상품 -->
<div
class="glass-card"
style="flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; padding: 15px;"
>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h2 style="font-size: 1.2rem; color: #000000; margin: 0; white-space: nowrap">
2. 추출할 상품
</h2>
<div style="display: flex; align-items: center; gap: 5px; margin-left: 10px; flex: 1; justify-content: flex-end;">
<input
type="text"
id="ee-product-search"
placeholder="상품 이름 검색"
autocomplete="off"
style="flex: 0 1 200px; min-width: 0; padding: 4px 8px; font-size: 0.85rem; border: 1px solid #cbd5e0; border-radius: 4px; background: #fff; color: #2d3748;"
/>
<button
id="btn-ee-select-all"
class="btn btn-sm"
type="button"
style="padding: 4px 8px; font-size: 0.8rem; background: #e2e8f0; color: #4a5568; box-shadow: none; white-space: nowrap;"
>
전체 선택
</button>
<button
id="btn-ee-select-none"
class="btn btn-sm"
type="button"
style="padding: 4px 8px; font-size: 0.8rem; background: #e2e8f0; color: #4a5568; box-shadow: none; white-space: nowrap;"
>
해제
</button>
</div>
</div>
<div
id="ee-product-list"
style="flex: 1; overflow-y: auto; border: 1px solid #e2e8f0; border-radius: 4px; background: white; padding: 4px;"
>
<div style="padding: 20px; text-align: center; color: #a0aec0; font-size: 0.85rem;">
CSV를 업로드하면 상품 목록이 표시됩니다.
</div>
</div>
<div id="ee-selected-info" style="margin-top: 8px; font-size: 0.8rem; color: #4a5568"></div>
</div>
<!-- 3. 추출 조건 -->
<div
class="glass-card"
style="flex: 0 0 340px; width: 340px; display: flex; flex-direction: column; overflow: hidden; padding: 15px;"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0 0 10px 0">3. 추출 조건</h2>
<label
style="display: flex; align-items: flex-start; gap: 10px; padding: 12px; border: 1px solid #bee3f8; background: #ebf8ff; border-radius: 4px; cursor: pointer; margin-bottom: 8px;"
>
<input
type="radio"
name="ee-mode"
value="product"
checked
style="width: 17px; height: 17px; margin-top: 3px; flex-shrink: 0"
/>
<span>
<span style="font-weight: 700; font-size: 1.1rem; color: #2b6cb0">해당상품만 추출</span>
<span style="display: block; font-size: 0.9rem; color: #4a5568; margin-top: 4px; line-height: 1.45;">
선택한 상품이 들어있는 행만 남기고 나머지 행은 모두 삭제
</span>
</span>
</label>
<label
style="display: flex; align-items: flex-start; gap: 10px; padding: 12px; border: 1px solid #e2e8f0; background: #fff; border-radius: 4px; cursor: pointer; margin-bottom: 12px;"
>
<input
type="radio"
name="ee-mode"
value="order"
style="width: 17px; height: 17px; margin-top: 3px; flex-shrink: 0"
/>
<span>
<span style="font-weight: 700; font-size: 1.1rem; color: #2d3748">해당 주문 추출</span>
<span style="display: block; font-size: 0.9rem; color: #4a5568; margin-top: 4px; line-height: 1.45;">
선택한 상품이 들어있는 행의 주문번호(B열)와 같은 행은 모두 남김
</span>
</span>
</label>
<button
id="btn-ee-download"
class="btn btn-secondary"
type="button"
style="width: 100%; background: #1d6f42; color: white; border-color: #175c36; padding: 12px 6px; font-weight: bold; font-size: 1rem; line-height: 1.3;"
>
추출 결과 엑셀 다운로드
</button>
<div style="font-size: 0.75rem; color: #718096; line-height: 1.5; margin-top: 12px;">
다운로드 파일의 <b>N열</b>에는 <code>=L×M</code> 수식이 그대로 들어가고 셀 배경은
노란색으로 표시됩니다.
</div>
<div
id="ee-warning-box"
style="display: none; margin-top: 10px; background: #fffaf0; border: 1px solid #fbd38d; color: #975a16; border-radius: 4px; padding: 8px 10px; font-size: 0.8rem; line-height: 1.5;"
></div>
<div
id="ee-result-info"
style="margin-top: 10px; font-size: 0.85rem; color: #2d3748; line-height: 1.8;"
></div>
</div>
</div>
</div>
</section>
<!-- =========================
COUPANG MILKRUN TAB
========================== -->
<section
id="milkrun-tab"
class="tab-content flex-layout"
style="padding: 15px; height: 100%; position: relative"
>
<header>
<h1 style="color: #fff">쿠팡 밀크런 낱개 분해</h1>
</header>
<div
id="milkrun-loading-overlay"
style="
display: none;
position: absolute;
inset: 0;
z-index: 50;
background: rgba(255, 255, 255, 0.7);
align-items: center;
justify-content: center;
flex-direction: column;
gap: 12px;
"
>
<div class="milkrun-spinner"></div>
<div
id="milkrun-loading-text"
style="font-size: 1rem; font-weight: 600; color: #2d3748"
>
계산 중...
</div>
</div>
<div
class="milkrun-split-container"
style="display: flex; gap: 20px; flex: 1; overflow: hidden; margin-top: 10px"
>
<!-- 왼쪽 세로 묶음: 구글 시트 불러오기 + 붙여넣기 입력 -->
<div
style="
flex: 0 0 450px;
width: 450px;
max-width: 450px;
display: flex;
flex-direction: column;
gap: 12px;
overflow: hidden;
"
>
<!-- 구글 시트 불러오기 -->
<div class="glass-card" style="flex: 0 0 auto; padding: 15px; overflow: hidden">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<h2 style="font-size: 1.2rem; color: #000000; margin: 0">밀크런 캘린더</h2>
<button
id="btn-gsheet-refresh"
class="btn btn-sm"
type="button"
title="구글 시트에서 다시 읽어옵니다"
style="padding: 5px 10px; background: #e2e8f0; color: #4a5568; box-shadow: none;"
>
새로고침
</button>
</div>
<div
id="gsheet-message"
style="display: none; margin-top: 8px; border-radius: 4px; padding: 8px 10px; font-size: 0.8rem; line-height: 1.5;"
></div>
<div
id="gsheet-file-info"
style="display: none; margin-top: 8px; font-size: 0.8rem; color: #4a5568;"
></div>
<div
id="gsheet-calendar"
style="display: none; margin-top: 8px; border: 1px solid #e2e8f0; border-radius: 4px; background: #fff; padding: 8px;"
></div>
<div
id="gsheet-other-sheets"
style="display: none; margin-top: 6px; font-size: 0.75rem; color: #718096;"
></div>
</div>
<!-- 붙여넣기 입력 영역 -->
<div
class="glass-card"
style="
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0">붙여넣기 입력</h2>
<div style="display: flex; gap: 8px">
<button
id="btn-milkrun-analyze"
class="btn btn-primary btn-sm"
style="background: #3182ce; padding: 5px 12px"
>
분석
</button>
<button
id="btn-milkrun-clear"
class="btn btn-secondary btn-sm"
style="padding: 5px 12px"
>
지우기
</button>
</div>
</div>
<div style="font-size: 0.78rem; color: #718096; margin-bottom: 8px">
쿠팡 밀크런 내용을 그대로 붙여넣으세요 (제품코드 / 제품명 / 수량). "MT-7000_2"처럼
코드 끝에 "_숫자"가 붙으면 해당 숫자만큼 곱해서 계산합니다.
</div>
<textarea
id="milkrun-input"
placeholder="제품코드 제품명 수량&#10;MT-7000_2 점보 7,000ml x2 108&#10;MS-1004 미라네 4호세트 120"
style="
flex: 1;
resize: none;
border: 1px solid #e2e8f0;
border-radius: 4px;
padding: 10px;
font-family: &quot;Consolas&quot;, monospace;
font-size: 0.85rem;
white-space: pre;
"
></textarea>
</div>
</div>
<!-- 라인별 분해 확인 영역 -->
<div
class="glass-card"
style="
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0">라인별 분해 확인</h2>
<span
id="milkrun-lines-info"
style="font-size: 0.8rem; color: #4a5568"
></span>
</div>
<div
style="
flex: 1;
overflow-y: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
"
>
<table
style="
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 0.76rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #ebf8ff;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th style="padding: 6px 8px; font-weight: 600; white-space: nowrap">
입력 코드
</th>
<th
style="
padding: 6px 8px;
font-weight: 600;
text-align: right;
white-space: nowrap;
"
>
입력 수량
</th>
<th style="padding: 6px 8px; font-weight: 600">분해 결과</th>
</tr>
</thead>
<tbody id="milkrun-lines-tbody"></tbody>
</table>
</div>
</div>
<!-- 분석 결과 영역 -->
<div
class="glass-card"
style="
flex: 0 0 420px;
width: 420px;
max-width: 420px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
"
>
<h2 style="font-size: 1.2rem; color: #000000; margin: 0">낱개 코드 합계</h2>
<div style="display: flex; align-items: center; gap: 10px">
<span
id="milkrun-summary-info"
style="font-size: 0.8rem; color: #4a5568; text-align: right; line-height: 1.4"
></span>
<button
id="btn-milkrun-download"
class="btn btn-secondary btn-sm"
style="
background: #1d6f42;
color: white;
border-color: #175c36;
padding: 5px 10px;
text-align: center;
line-height: 1.3;
"
>
엑셀<br />다운로드
</button>
</div>
</div>
<div
id="milkrun-unresolved-box"
style="
display: none;
background: #fff5f5;
border: 1px solid #feb2b2;
color: #c53030;
border-radius: 4px;
padding: 8px 10px;
margin-bottom: 10px;
font-size: 0.85rem;
"
></div>
<div
style="
flex: 1;
overflow-y: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
"
>
<table
style="
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 0.78rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #ebf8ff;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th style="padding: 7px 8px; font-weight: 600; white-space: nowrap">
사방넷 코드
</th>
<th style="padding: 7px 8px; font-weight: 600; white-space: nowrap">
낱개 코드
</th>
<th style="padding: 7px 8px; font-weight: 600; white-space: nowrap">
상품 이름
</th>
<th
style="
padding: 7px 8px;
font-weight: 600;
text-align: right;
white-space: nowrap;
"
>
합계 수량
</th>
</tr>
</thead>
<tbody id="milkrun-totals-tbody"></tbody>
</table>
</div>
</div>
</div>
</section>
<!-- =========================
RETURN MANAGEMENT TAB
========================== -->
<section
id="return-tab"
class="tab-content flex-layout"
style="padding: 15px; height: 100%; position: relative"
>
<header>
<h1 style="color: #fff">반품관리 (반품 신청 및 입고 처리)</h1>
</header>
<div
class="return-split-container"
style="display: flex; gap: 20px; flex: 1; overflow: hidden; margin-top: 10px"
>
<!-- 반품 신청 (좌측 50%) -->
<div
class="glass-card"
style="
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<!-- 반품 신청 폼 -->
<form
id="form-return-request"
style="margin-bottom: 15px; display: flex; flex-direction: column"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #3182ce;
padding-bottom: 5px;
margin-bottom: 15px;
"
>
<h2
style="
font-size: 1.2rem;
color: #000000;
margin: 0;
display: flex;
align-items: center;
gap: 8px;
"
>
📋 반품 신청
<button
type="button"
class="btn-detail-toggle"
onclick="
this.closest('form').classList.toggle('show-details');
this.textContent = this.closest('form').classList.contains('show-details')
? '접기 ▲'
: '상세 ▼';
"
>
상세 ▼
</button>
</h2>
<div style="display: flex; gap: 5px">
<button
type="button"
id="btn-email-req"
class="btn btn-secondary"
style="
height: 40px;
background: #ed8936;
color: white;
font-size: 0.8rem;
padding: 0 10px;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
"
>
<span style="font-size: 1.4rem">📧</span> 반품 신청하기
</button>
<button
type="submit"
class="btn btn-primary"
style="
width: 110px;
height: 40px;
background: #3182ce;
font-size: 0.8rem;
padding: 0;
"
>
반품 신청 등록
</button>
</div>
</div>
<input
type="hidden"
id="req-id"
/>
<div style="display: flex; flex-direction: column; gap: 10px">
<div style="display: flex; gap: 10px; flex-wrap: wrap">
<div
class="form-group"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem"
>송장번호 <span style="color: #e53e3e">*</span></label
>
<input
type="text"
id="req-tracking-no"
placeholder="입력 후 Enter"
required
style="
border: 2px solid #3182ce;
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
"
/>
</div>
<div
class="form-group mobile-hide"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">신청날짜</label>
<input
type="date"
id="req-date"
required
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
"
/>
</div>
<div
class="form-group mobile-hide"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">쇼핑몰</label>
<input
type="text"
id="req-mall"
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
<div
class="form-group"
style="margin-bottom: 0; width: 100px"
>
<label style="font-weight: 600; font-size: 0.8rem">신청구분</label>
<select
id="req-type"
required
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
border: 1px solid #cbd5e0;
border-radius: 4px;
"
>
<option value="단순변심">단순변심</option>
<option value="상품불량">상품불량</option>
<option value="오배송">오배송</option>
<option value="파손">파손</option>
<option value="맞교환">맞교환</option>
<option value="기타">기타</option>
</select>
</div>
</div>
<div
class="mobile-hide"
style="display: flex; gap: 10px; flex-wrap: wrap"
>
<div
class="form-group"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">수령인명</label>
<input
type="text"
id="req-name"
required
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
<div
class="form-group"
style="margin-bottom: 0; width: 145px"
>
<label style="font-weight: 600; font-size: 0.8rem">휴대폰번호</label>
<input
type="text"
id="req-phone"
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
<div
class="form-group"
style="margin-bottom: 0; flex: 1"
>
<label style="font-weight: 600; font-size: 0.8rem">주소</label>
<input
type="text"
id="req-address"
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
</div>
<div style="display: flex; gap: 10px; flex-wrap: wrap">
<div
class="form-group"
style="margin-bottom: 0; flex: 1"
>
<label style="font-weight: 600; font-size: 0.8rem">비고</label>
<input
type="text"
id="req-remarks"
placeholder="참고사항 입력"
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
"
/>
</div>
</div>
</div>
</form>
<!-- 반품 신청 리스트 표기 -->
<h3
style="
font-size: 0.75rem;
margin-bottom: 5px;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<span>신청 목록</span
><label
style="
cursor: pointer;
font-weight: normal;
margin: 0;
display: flex;
align-items: center;
gap: 4px;
"
><input
type="checkbox"
id="chk-exclude-received"
/>
입고완료 제외</label
>
</h3>
<div
style="
flex: 1;
overflow: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
"
>
<table
style="
width: 100%;
min-width: 780px;
table-layout: fixed;
border-collapse: collapse;
text-align: left;
font-size: 0.75rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #ebf8ff;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th style="padding: 8px; width: 30px; text-align: center">
<input
type="checkbox"
id="chk-all-req"
/>
</th>
<th
style="padding: 8px; width: 100px; text-align: center; white-space: nowrap"
>
날짜
</th>
<th
style="padding: 8px; width: 90px; text-align: center; white-space: nowrap"
>
수령인
</th>
<th
style="padding: 8px; width: 130px; text-align: center; white-space: nowrap"
>
휴대폰번호
</th>
<th
style="padding: 8px; width: 110px; text-align: center; white-space: nowrap"
>
송장번호
</th>
<th
style="padding: 8px; width: 65px; text-align: center; white-space: nowrap"
>
상태
</th>
<th
style="padding: 8px; width: 215px; text-align: center; white-space: nowrap"
>
비고
</th>
<th
style="padding: 8px; width: 40px; text-align: center; white-space: nowrap"
>
관리
</th>
</tr>
</thead>
<tbody id="tbody-return-requests"></tbody>
</table>
</div>
</div>
<!-- 반품 입고 (우측 50%) -->
<div
class="glass-card"
style="
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 15px;
"
>
<!-- 반품 입고 폼 -->
<form
id="form-return-receive"
data-edit="true"
style="margin-bottom: 15px"
>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #38a169;
padding-bottom: 5px;
margin-bottom: 15px;
"
>
<h2
style="
font-size: 1.2rem;
color: #000000;
margin: 0;
display: flex;
align-items: center;
gap: 8px;
"
>
📦 반품 입고
<button
type="button"
class="btn-detail-toggle"
onclick="
this.closest('form').classList.toggle('show-details');
this.textContent = this.closest('form').classList.contains('show-details')
? '접기 ▲'
: '상세 ▼';
"
>
상세 ▼
</button>
</h2>
<div style="display: flex; gap: 5px">
<button
type="button"
id="btn-bulk-receive"
class="btn btn-secondary"
style="
width: 110px;
height: 40px;
background: #4a5568;
color: white;
font-size: 0.8rem;
padding: 0;
"
>
송장일괄 입고
</button>
<button
type="submit"
class="btn btn-primary"
style="
width: 110px;
height: 40px;
background: #38a169;
font-size: 0.8rem;
padding: 0;
"
>
반품 입고 등록
</button>
</div>
</div>
<input
type="hidden"
id="rec-id"
/>
<div style="display: flex; flex-direction: column; gap: 10px">
<!-- Line 1 -->
<div style="display: flex; gap: 10px; flex-wrap: wrap">
<div
class="form-group"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem"
>송장번호 <span style="color: #e53e3e">*</span></label
>
<input
type="text"
id="rec-tracking-no"
placeholder="입력 후 Enter"
required
style="
border: 2px solid #38a169;
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
"
/>
</div>
<div
class="form-group mobile-hide"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">입고날짜</label>
<input
type="date"
id="rec-date"
required
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
"
/>
</div>
<div
class="form-group mobile-hide"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">쇼핑몰</label>
<input
type="text"
id="rec-mall"
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
<div
class="form-group"
style="margin-bottom: 0; width: 120px"
>
<label style="font-weight: 600; font-size: 0.8rem">입고상태</label>
<select
id="rec-status"
required
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
border: 1px solid #cbd5e0;
border-radius: 4px;
"
>
<option
value="대기"
selected
>
대기
</option>
<option value="환불대기">환불대기</option>
<option value="환불완료">환불완료</option>
<option value="교환완료">교환완료</option>
</select>
</div>
</div>
<!-- Line 2 -->
<div
class="mobile-hide"
style="display: flex; gap: 10px; flex-wrap: wrap"
>
<div
class="form-group"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">이름</label>
<input
type="text"
id="rec-name"
required
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
<div
class="form-group"
style="margin-bottom: 0; width: 135px"
>
<label style="font-weight: 600; font-size: 0.8rem">휴대폰번호</label>
<input
type="text"
id="rec-phone"
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
<div
class="form-group"
style="margin-bottom: 0; flex: 1"
>
<label style="font-weight: 600; font-size: 0.8rem">주소</label>
<input
type="text"
id="rec-address"
readonly
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
border: 1px solid #cbd5e0;
border-radius: 4px;
background-color: #edf2f7;
cursor: not-allowed;
color: #4a5568;
"
/>
</div>
</div>
<!-- Line 3 -->
<div style="display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end">
<div
class="form-group"
style="margin-bottom: 0; flex: 1"
>
<label style="font-weight: 600; font-size: 0.8rem">비고</label>
<input
type="text"
id="rec-remarks"
placeholder="환불 처리 여부 등"
style="
width: 100%;
height: 26px;
padding: 2px 5px;
font-size: 0.85rem;
box-sizing: border-box;
"
/>
</div>
</div>
</div>
</form>
<!-- 송장일괄 입고 모달 -->
<div
id="bulk-receive-modal"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
"
>
<div
style="
background: white;
padding: 20px;
border-radius: 8px;
width: 325px;
display: flex;
flex-direction: column;
gap: 15px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
"
>
<h3 style="margin: 0; font-size: 1.2rem; color: #2d3748">송장일괄 입고</h3>
<div style="display: flex; align-items: center; justify-content: space-between">
<span
style="font-size: 0.9rem; font-weight: bold; color: #2d3748; line-height: 1.4"
>
송장 앞 숫자 4자리
<input
type="text"
id="bulk-prefix-input"
style="
width: 45px;
text-align: center;
border: 1px solid #cbd5e0;
border-radius: 4px;
padding: 2px;
font-size: 0.9rem;
margin: 0 4px;
"
maxlength="4"
/><br />제외하고 입력 하세요.
</span>
<button
type="button"
id="btn-bulk-prefix-save"
class="btn btn-secondary"
style="
padding: 4px 12px;
font-size: 0.9rem;
background: #4a5568;
color: white;
white-space: nowrap;
border: none;
"
>
설정
</button>
</div>
<div class="bulk-tracking-editor">
<div
id="bulk-tracking-line-numbers"
class="bulk-tracking-line-numbers"
aria-hidden="true"
>1</div>
<textarea
id="bulk-tracking-numbers"
class="bulk-tracking-input"
wrap="off"
spellcheck="false"
aria-label="송장 번호 일괄 입력"
></textarea>
</div>
<div style="display: flex; justify-content: flex-end; gap: 10px">
<button
type="button"
id="btn-bulk-cancel"
class="btn btn-secondary"
style="padding: 8px 16px"
>
취소
</button>
<button
type="button"
id="btn-bulk-submit"
class="btn btn-primary"
style="padding: 8px 16px; background: #3182ce"
>
일괄 등록
</button>
</div>
</div>
</div>
<!-- 반품 입고 리스트 표기 -->
<h3
style="
font-size: 0.75rem;
margin-bottom: 5px;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<span>입고 목록</span
><label
style="
cursor: pointer;
font-weight: normal;
margin: 0;
display: flex;
align-items: center;
gap: 4px;
"
><input
type="checkbox"
id="chk-exclude-completed"
/>
환불/교환완료 제외</label
>
</h3>
<div
style="
flex: 1;
overflow: auto;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: white;
"
>
<table
style="
width: 100%;
min-width: 780px;
table-layout: fixed;
border-collapse: collapse;
text-align: left;
font-size: 0.75rem;
"
>
<thead
style="
position: sticky;
top: 0;
background: #f0fff4;
box-shadow: 0 1px 0 #e2e8f0;
z-index: 10;
"
>
<tr>
<th
style="padding: 8px; width: 100px; text-align: center; white-space: nowrap"
>
입고날짜
</th>
<th
style="padding: 8px; width: 90px; text-align: center; white-space: nowrap"
>
수령인
</th>
<th
style="padding: 8px; width: 130px; text-align: center; white-space: nowrap"
>
휴대폰번호
</th>
<th
style="padding: 8px; width: 110px; text-align: center; white-space: nowrap"
>
송장번호
</th>
<th
style="padding: 8px; width: 85px; text-align: center; white-space: nowrap"
>
쇼핑몰
</th>
<th
style="padding: 8px; width: 65px; text-align: center; white-space: nowrap"
>
입고상태
</th>
<th
style="padding: 8px; width: 160px; text-align: center; white-space: nowrap"
>
비고
</th>
<th
style="padding: 8px; width: 40px; text-align: center; white-space: nowrap"
>
관리
</th>
</tr>
</thead>
<tbody id="tbody-return-receivings"></tbody>
</table>
</div>
</div>
</div>
</section>
<!-- =========================
VERSION HISTORY TAB
========================== -->
{% include 'version_history.html' %}
</main>
</div>
<script src="{{ root_path }}/static/js/app.js?v=69"></script>
<script src="{{ root_path }}/static/js/mall_event.js?v=7"></script>
<script src="{{ root_path }}/static/js/milkrun_gsheet.js?v=7"></script>
<!-- Toast Notification -->
<div
id="toast-notification"
style="
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 10px 20px;
border-radius: 5px;
font-size: 0.9rem;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
"
>
클립보드로 주문 내용이 복사되었습니다.
</div>
<!-- Exclusion Modal -->
<div
id="exclude-modal"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
"
>
<div
class="glass-card"
style="
background: #fff;
width: 450px;
padding: 25px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
max-width: 90%;
"
>
<h3
style="
margin-top: 0;
color: #2b6cb0;
border-bottom: 2px solid #3182ce;
padding-bottom: 8px;
margin-bottom: 15px;
"
>
🛒 발주 입력 확인
</h3>
<p style="font-size: 0.95rem; color: #4a5568; line-height: 1.4">
아래 상품 중에서 총 금액 계산에서 <br /><strong style="color: #e53e3e"
>제외할 상품을 선택</strong
>
하고 [입력] 버튼을 눌러주세요.
</p>
<div
id="exclude-items-list"
style="
max-height: 300px;
overflow-y: auto;
margin: 15px 0;
border: 1px solid #e2e8f0;
border-radius: 4px;
padding: 10px;
background: #f7fafc;
display: flex;
flex-direction: column;
gap: 8px;
"
>
<!-- checkboxes injected here -->
</div>
<div
style="
font-size: 1.1rem;
font-weight: bold;
text-align: right;
color: #2d3748;
padding-bottom: 15px;
border-bottom: 1px dashed #cbd5e0;
margin-bottom: 10px;
"
>
최종 금액:
<span
id="exclude-modal-totalAmount"
style="color: #e53e3e"
>0</span
>
</div>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
"
>
<label
style="
font-weight: bold;
color: #3182ce;
display: flex;
align-items: center;
gap: 5px;
cursor: pointer;
font-size: 0.95rem;
"
>
<input
type="checkbox"
id="chk-sample-send"
style="transform: scale(1.2); cursor: pointer"
/>
샘플 발송
</label>
<div style="display: flex; justify-content: flex-end; gap: 10px">
<button
id="btn-exclude-cancel"
class="btn btn-secondary"
style="padding: 8px 16px"
>
취소
</button>
<button
id="btn-exclude-submit"
class="btn btn-primary"
style="padding: 8px 16px; background: #3182ce"
>
입력
</button>
</div>
</div>
</div>
</div>
<!-- Code Single Item Modal -->
<div
id="single-item-modal"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
"
>
<div
class="glass-card"
style="
background: #fff;
width: 400px;
padding: 25px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
max-width: 90%;
"
>
<h3
id="modal-single-title"
style="
margin-top: 0;
color: #2b6cb0;
border-bottom: 2px solid #3182ce;
padding-bottom: 8px;
margin-bottom: 15px;
"
>
📦 단품 추가
</h3>
<div style="display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px">
<label
style="display: flex; flex-direction: column; font-size: 0.9rem; font-weight: bold"
>
단품 아이템 코드
<input
type="text"
id="sin-item-code"
style="padding: 8px; border: 1px solid #cbd5e0; border-radius: 4px; margin-top: 4px"
placeholder="예: ITEM_001"
/>
<span
id="sin-item-warn"
style="color: #e53e3e; font-size: 0.8rem; margin-top: 4px; display: none"
>⚠️ 이미 존재하는 단품 코드입니다!</span
>
</label>
<label
style="display: flex; flex-direction: column; font-size: 0.9rem; font-weight: bold"
>
사방넷 코드 (형식: XXXXXX-0001)
<input
type="text"
id="sin-sabangnet-code"
style="padding: 8px; border: 1px solid #cbd5e0; border-radius: 4px; margin-top: 4px"
placeholder="102845-0001"
/>
</label>
<label
style="display: flex; flex-direction: column; font-size: 0.9rem; font-weight: bold"
>
단품 이름
<input
type="text"
id="sin-name"
style="padding: 8px; border: 1px solid #cbd5e0; border-radius: 4px; margin-top: 4px"
placeholder="상품 이름"
/>
</label>
</div>
<div style="display: flex; justify-content: flex-end; gap: 10px">
<button
id="btn-sin-cancel"
class="btn btn-secondary"
style="padding: 8px 16px"
>
취소
</button>
<button
id="btn-sin-save"
class="btn btn-primary"
style="padding: 8px 16px; background: #3182ce"
>
저장
</button>
</div>
</div>
</div>
<!-- Code Set Item Modal -->
<div
id="set-item-modal"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
"
>
<div
class="glass-card"
style="
background: #fff;
width: 550px;
padding: 25px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
max-width: 90%;
"
>
<h3
id="modal-set-title"
style="
margin-top: 0;
color: #dd6b20;
border-bottom: 2px solid #ed8936;
padding-bottom: 8px;
margin-bottom: 15px;
"
>
🍱 세트 추가
</h3>
<div style="display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px">
<div style="display: flex; gap: 10px">
<label
style="
display: flex;
flex-direction: column;
font-size: 0.9rem;
font-weight: bold;
flex: 1;
"
>
세트 아이템 코드
<input
type="text"
id="set-item-code"
style="padding: 8px; border: 1px solid #cbd5e0; border-radius: 4px; margin-top: 4px"
placeholder="예: SET_001"
/>
<span
id="set-item-warn"
style="color: #e53e3e; font-size: 0.8rem; margin-top: 4px; display: none"
>⚠️ 이미 존재하는 세트 코드입니다!</span
>
</label>
<label
style="
display: flex;
flex-direction: column;
font-size: 0.9rem;
font-weight: bold;
flex: 1;
"
>
세트 이름
<input
type="text"
id="set-name"
style="padding: 8px; border: 1px solid #cbd5e0; border-radius: 4px; margin-top: 4px"
placeholder="세트 이름"
/>
</label>
</div>
<hr style="border: 0; border-top: 1px dashed #cbd5e0" />
<div style="margin-top: 5px">
<h4 style="margin: 0 0 10px 0; color: #4a5568; font-size: 0.95rem">세트 구성품 등록</h4>
<div
id="set-components-wrapper"
style="
display: flex;
flex-direction: column;
gap: 8px;
max-height: 200px;
overflow-y: auto;
padding: 5px;
border: 1px solid #e2e8f0;
border-radius: 4px;
background: #f7fafc;
"
>
<!-- components rows go here -->
</div>
<button
id="btn-add-set-component"
class="btn btn-secondary btn-sm"
style="
margin-top: 8px;
width: 100%;
border: 1px dashed #a0aec0;
background: transparent;
color: #4a5568;
"
>
+단품 추가
</button>
</div>
</div>
<div style="display: flex; justify-content: flex-end; gap: 10px">
<button
id="btn-set-cancel"
class="btn btn-secondary"
style="padding: 8px 16px"
>
취소
</button>
<button
id="btn-set-save"
class="btn btn-accent"
style="padding: 8px 16px; background: #ed8936"
>
저장
</button>
</div>
</div>
</div>
<!-- 업데이트 알림 모달 -->
<div
id="update-notice-modal"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 9999;
align-items: center;
justify-content: center;
"
>
<div
style="
background: white;
padding: 30px;
border-radius: 12px;
width: 450px;
display: flex;
flex-direction: column;
gap: 20px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
"
>
<div
style="
display: flex;
align-items: center;
gap: 10px;
border-bottom: 2px solid #3182ce;
padding-bottom: 10px;
"
>
<span style="font-size: 1.8rem">🎉</span>
<h3 style="margin: 0; font-size: 1.4rem; color: #2b6cb0">업데이트 안내</h3>
</div>
<p style="font-size: 1.1rem; margin: 0; color: #2d3748; line-height: 1.6">
프로그램이
<strong
style="color: #e53e3e; font-size: 1.2rem"
id="update-notice-version"
></strong>
버전으로 업데이트 되었습니다.<br /><br />
<strong>Ver History</strong>에서 내용을 확인 해주세요!!
</p>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
"
>
<label
style="
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
color: #4a5568;
font-size: 0.95rem;
"
>
<input
type="checkbox"
id="chk-hide-update-notice"
style="width: 16px; height: 16px"
/>
다시는 메시지 보지 않기
</label>
<button
type="button"
id="btn-close-update-notice"
class="btn btn-primary"
style="
padding: 10px 24px;
background: #3182ce;
font-size: 1rem;
border-radius: 6px;
cursor: pointer;
color: white;
border: none;
"
>
확인
</button>
</div>
</div>
</div>
</body>
</html>