feat: 전화접수 관리 — 접수 리스트 컬럼 보강·헤더 정렬, 배달일 수정 저장
- 접수 리스트에 접수일/배달일/금액 컬럼 추가, 헤더 클릭 정렬(번호·접수일·배달일·판매소·금액·상태, 오름/내림 토글) - 우측 상세에서 배달일을 date 입력으로 수정 가능, 저장 시 so_delivery_date 변경 반영 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -22,28 +22,15 @@
|
||||
<table class="w-full data-table text-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-14 text-center">번호</th>
|
||||
<th class="text-left">판매소</th>
|
||||
<th class="w-28 text-center">접수일</th>
|
||||
<th class="w-24 text-center">상태</th>
|
||||
<th class="w-12 text-center sort-th cursor-pointer select-none" data-sort="so_idx" data-type="num">번호<span class="sort-ind"></span></th>
|
||||
<th class="w-24 text-center sort-th cursor-pointer select-none" data-sort="so_order_date" data-type="str">접수일<span class="sort-ind"></span></th>
|
||||
<th class="w-24 text-center sort-th cursor-pointer select-none" data-sort="so_delivery_date" data-type="str">배달일<span class="sort-ind"></span></th>
|
||||
<th class="text-left sort-th cursor-pointer select-none" data-sort="so_ds_name" data-type="str">판매소<span class="sort-ind"></span></th>
|
||||
<th class="w-24 text-right sort-th cursor-pointer select-none" data-sort="so_total_amount" data-type="num">금액<span class="sort-ind"></span></th>
|
||||
<th class="w-16 text-center sort-th cursor-pointer select-none" data-sort="so_status" data-type="str">상태<span class="sort-ind"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="order-list-body">
|
||||
<?php foreach (($orders ?? []) as $row): ?>
|
||||
<?php $isCancelled = (($row['so_status'] ?? 'normal') === 'cancelled'); ?>
|
||||
<tr class="order-list-row cursor-pointer hover:bg-blue-50 <?= $isCancelled ? 'bg-gray-50 text-gray-400' : '' ?>" data-order-id="<?= esc((string) ($row['so_idx'] ?? 0), 'attr') ?>">
|
||||
<td class="text-center"><?= esc((string) ($row['so_idx'] ?? 0)) ?></td>
|
||||
<td class="text-left pl-2"><?= esc((string) ($row['so_ds_name'] ?? '')) ?></td>
|
||||
<td class="text-center"><?= esc((string) ($row['so_order_date'] ?? '')) ?></td>
|
||||
<td class="text-center"><?= $isCancelled ? '취소' : '정상' ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($orders)): ?>
|
||||
<tr>
|
||||
<td colspan="4" class="text-center py-8 text-gray-400">전화 주문 데이터가 없습니다.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
<tbody id="order-list-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
@@ -65,7 +52,9 @@
|
||||
<div><span class="font-semibold text-gray-700 inline-block w-20">결제수단</span> <span id="detail-payment">-</span></div>
|
||||
<div class="md:col-span-2"><span class="font-semibold text-gray-700 inline-block w-20">주소</span> <span id="detail-shop-addr">-</span></div>
|
||||
<div><span class="font-semibold text-gray-700 inline-block w-20">접수일</span> <span id="detail-order-date">-</span></div>
|
||||
<div><span class="font-semibold text-gray-700 inline-block w-20">배달일</span> <span id="detail-delivery-date">-</span></div>
|
||||
<div class="flex items-center"><span class="font-semibold text-gray-700 inline-block w-20">배달일</span>
|
||||
<input type="date" lang="ko" name="so_delivery_date" id="detail-delivery-date-input" class="border border-gray-300 rounded px-2 py-0.5 text-sm"/>
|
||||
</div>
|
||||
<div><span class="font-semibold text-gray-700 inline-block w-20">상태</span> <span id="detail-status">-</span></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -136,8 +125,14 @@
|
||||
t('detail-payment', order ? order.so_payment_type : '');
|
||||
t('detail-shop-addr', order ? order.ds_addr : '');
|
||||
t('detail-order-date', order ? order.so_order_date : '');
|
||||
t('detail-delivery-date', order ? order.so_delivery_date : '');
|
||||
t('detail-status', order ? ((order.so_status === 'cancelled') ? '취소' : '정상') : '');
|
||||
// 배달일 — 수정 가능한 date 입력
|
||||
var dd = document.getElementById('detail-delivery-date-input');
|
||||
if (dd) {
|
||||
var v = order && order.so_delivery_date ? String(order.so_delivery_date) : '';
|
||||
dd.value = /^\d{4}-\d{2}-\d{2}/.test(v) ? v.slice(0, 10) : '';
|
||||
dd.disabled = !order || order.so_status === 'cancelled';
|
||||
}
|
||||
}
|
||||
|
||||
function calcRow(tr) {
|
||||
@@ -241,12 +236,54 @@
|
||||
recalcTotals();
|
||||
}
|
||||
|
||||
// ── 접수 리스트 렌더 + 헤더 클릭 정렬 ──────────────────────────
|
||||
let sortKey = 'so_idx', sortDir = 'desc', selectedId = null;
|
||||
const esc = (s) => String(s == null ? '' : s).replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' }[c]));
|
||||
|
||||
function rowHtml(o) {
|
||||
const cancelled = o.so_status === 'cancelled';
|
||||
const dDate = o.so_delivery_date ? String(o.so_delivery_date).slice(0, 10) : '';
|
||||
return `<tr class="order-list-row cursor-pointer hover:bg-blue-50 ${cancelled ? 'bg-gray-50 text-gray-400' : ''} ${String(o.so_idx) === String(selectedId) ? 'bg-blue-100' : ''}" data-order-id="${o.so_idx}">
|
||||
<td class="text-center">${o.so_idx}</td>
|
||||
<td class="text-center">${esc(o.so_order_date)}</td>
|
||||
<td class="text-center">${esc(dDate)}</td>
|
||||
<td class="text-left pl-2">${esc(o.so_ds_name)}</td>
|
||||
<td class="text-right pr-2">${nf(o.so_total_amount || 0)}</td>
|
||||
<td class="text-center">${cancelled ? '취소' : '정상'}</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
function renderList() {
|
||||
const th = document.querySelector('.sort-th[data-sort="' + sortKey + '"]');
|
||||
const type = th ? th.dataset.type : 'str';
|
||||
const arr = orders.slice().sort((a, b) => {
|
||||
let va = a[sortKey], vb = b[sortKey];
|
||||
if (type === 'num') { va = Number(va || 0); vb = Number(vb || 0); return sortDir === 'asc' ? va - vb : vb - va; }
|
||||
va = String(va || ''); vb = String(vb || '');
|
||||
return sortDir === 'asc' ? va.localeCompare(vb, 'ko') : vb.localeCompare(va, 'ko');
|
||||
});
|
||||
listBody.innerHTML = arr.length
|
||||
? arr.map(rowHtml).join('')
|
||||
: '<tr><td colspan="6" class="text-center py-8 text-gray-400">전화 주문 데이터가 없습니다.</td></tr>';
|
||||
document.querySelectorAll('.sort-th .sort-ind').forEach((s) => { s.textContent = ''; });
|
||||
if (th) th.querySelector('.sort-ind').textContent = sortDir === 'asc' ? ' ▲' : ' ▼';
|
||||
}
|
||||
|
||||
document.querySelectorAll('.sort-th').forEach((th) => {
|
||||
th.addEventListener('click', () => {
|
||||
const k = th.dataset.sort;
|
||||
if (sortKey === k) { sortDir = sortDir === 'asc' ? 'desc' : 'asc'; } else { sortKey = k; sortDir = 'asc'; }
|
||||
renderList();
|
||||
});
|
||||
});
|
||||
|
||||
listBody?.addEventListener('click', (e) => {
|
||||
const tr = e.target.closest('.order-list-row');
|
||||
if (!tr) return;
|
||||
selectedId = tr.dataset.orderId;
|
||||
listBody.querySelectorAll('.order-list-row').forEach((row) => row.classList.remove('bg-blue-100'));
|
||||
tr.classList.add('bg-blue-100');
|
||||
renderDetail(tr.dataset.orderId);
|
||||
renderDetail(selectedId);
|
||||
});
|
||||
|
||||
detailBody?.addEventListener('input', (e) => {
|
||||
@@ -268,10 +305,12 @@
|
||||
}
|
||||
});
|
||||
|
||||
renderList();
|
||||
const firstRow = listBody?.querySelector('.order-list-row');
|
||||
if (firstRow) {
|
||||
selectedId = firstRow.dataset.orderId;
|
||||
firstRow.classList.add('bg-blue-100');
|
||||
renderDetail(firstRow.dataset.orderId);
|
||||
renderDetail(selectedId);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user