Compare commits
2 Commits
6c421153e4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
215d87f991 | ||
|
|
dc5c38d242 |
@@ -65,6 +65,7 @@ $routes->group('bag', ['filter' => 'loginAuth'], static function ($routes): void
|
||||
$routes->get('manual/(:segment)', 'Bag::manualPage/$1');
|
||||
$routes->post('activity/print-log', 'Bag::printLog'); // 인쇄 활동 기록(beacon)
|
||||
$routes->post('pref/font-scale', 'Bag::saveFontScale'); // 계정별·메뉴별 글자크기 저장
|
||||
$routes->post('pref/workspace-tabs', 'Bag::saveWorkspaceTabs'); // 계정별 워크스페이스 탭 상태 저장(자동 복원)
|
||||
});
|
||||
|
||||
$routes->get('bag/number-lookup', 'Bag::numberLookup');
|
||||
@@ -81,6 +82,7 @@ $routes->get('bag/order/phone', 'Bag::phoneOrderCreate');
|
||||
$routes->get('bag/order/phone/manage', 'Bag::phoneOrderManage');
|
||||
$routes->post('bag/order/phone/manage/update', 'Bag::phoneOrderUpdate');
|
||||
$routes->post('bag/order/phone/manage/scan', 'Bag::phoneOrderManageScan');
|
||||
$routes->post('bag/order/phone/manage/paid', 'Bag::phoneOrderMarkPaid');
|
||||
$routes->post('bag/order/phone/manage/cancel/(:num)', 'Bag::phoneOrderCancel/$1');
|
||||
$routes->get('bag/order/phone/receipt/(:num)', 'Bag::phoneOrderReceipt/$1');
|
||||
$routes->get('bag/order/change', 'Bag::orderChange');
|
||||
|
||||
@@ -274,6 +274,70 @@ SQL);
|
||||
return $this->response->setJSON(['ok' => true, 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
/** member_workspace_tabs 테이블 보장(없으면 생성) */
|
||||
private function ensureWorkspaceTabsTable(\CodeIgniter\Database\BaseConnection $db): void
|
||||
{
|
||||
if ($db->tableExists('member_workspace_tabs')) {
|
||||
return;
|
||||
}
|
||||
$db->query(<<<'SQL'
|
||||
CREATE TABLE IF NOT EXISTS `member_workspace_tabs` (
|
||||
`mwt_mb_idx` INT UNSIGNED NOT NULL,
|
||||
`mwt_state` MEDIUMTEXT NULL,
|
||||
`mwt_updated` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`mwt_mb_idx`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
SQL);
|
||||
}
|
||||
|
||||
/** 계정별 워크스페이스 탭 상태 조회(자동 복원용). 없으면 'null'. */
|
||||
public function loadWorkspaceTabsState(int $mbIdx): string
|
||||
{
|
||||
if ($mbIdx <= 0) {
|
||||
return 'null';
|
||||
}
|
||||
$db = \Config\Database::connect();
|
||||
if (! $db->tableExists('member_workspace_tabs')) {
|
||||
return 'null';
|
||||
}
|
||||
$row = $db->table('member_workspace_tabs')->select('mwt_state')->where('mwt_mb_idx', $mbIdx)->get()->getRowArray();
|
||||
$s = (string) ($row['mwt_state'] ?? '');
|
||||
return $s !== '' ? $s : 'null';
|
||||
}
|
||||
|
||||
/** 계정별 워크스페이스 탭 상태 저장 (자동 복원) */
|
||||
public function saveWorkspaceTabs(): ResponseInterface
|
||||
{
|
||||
$mbIdx = (int) (session()->get('mb_idx') ?? 0);
|
||||
if ($mbIdx <= 0) {
|
||||
return $this->response->setJSON(['ok' => false, 'csrf' => csrf_hash()]);
|
||||
}
|
||||
$state = (string) ($this->request->getPost('state') ?? '');
|
||||
// 크기 제한 + JSON 유효성
|
||||
if (strlen($state) > 30000) {
|
||||
return $this->response->setJSON(['ok' => false, 'csrf' => csrf_hash()]);
|
||||
}
|
||||
if ($state !== '') {
|
||||
json_decode($state);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
return $this->response->setJSON(['ok' => false, 'csrf' => csrf_hash()]);
|
||||
}
|
||||
}
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$this->ensureWorkspaceTabsTable($db);
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$exists = $db->table('member_workspace_tabs')->where('mwt_mb_idx', $mbIdx)->countAllResults();
|
||||
if ($exists > 0) {
|
||||
$db->table('member_workspace_tabs')->where('mwt_mb_idx', $mbIdx)
|
||||
->update(['mwt_state' => $state, 'mwt_updated' => $now]);
|
||||
} else {
|
||||
$db->table('member_workspace_tabs')->insert(['mwt_mb_idx' => $mbIdx, 'mwt_state' => $state, 'mwt_updated' => $now]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['ok' => true, 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────
|
||||
// 기본정보관리 (단가·포장 단위 진입 허브)
|
||||
// ──────────────────────────────────────────────
|
||||
@@ -7896,6 +7960,37 @@ SQL;
|
||||
return redirect()->to(site_url('bag/order/phone/manage'))->with('success', '주문 수정 저장이 완료되었습니다.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 주문접수 관리 — 입금확인(so_paid) 수동 토글(JSON 응답).
|
||||
* 입금확인이 완료되어야 포장(스캔)이 가능하다.
|
||||
*/
|
||||
public function phoneOrderMarkPaid()
|
||||
{
|
||||
$lgIdx = $this->lgIdx();
|
||||
if (! $lgIdx) {
|
||||
return $this->response->setJSON(['ok' => false, 'message' => '지자체를 선택해 주세요.', 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
$soIdx = (int) ($this->request->getPost('so_idx') ?? 0);
|
||||
$paid = ((int) ($this->request->getPost('paid') ?? 0)) === 1 ? 1 : 0;
|
||||
if ($soIdx <= 0) {
|
||||
return $this->response->setJSON(['ok' => false, 'message' => '주문 값이 올바르지 않습니다.', 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
$orderModel = model(ShopOrderModel::class);
|
||||
$order = $orderModel->where('so_idx', $soIdx)->where('so_lg_idx', $lgIdx)->first();
|
||||
if (! $order) {
|
||||
return $this->response->setJSON(['ok' => false, 'message' => '선택한 주문을 찾을 수 없습니다.', 'csrf' => csrf_hash()]);
|
||||
}
|
||||
if ((string) ($order->so_status ?? '') === 'cancelled') {
|
||||
return $this->response->setJSON(['ok' => false, 'message' => '취소된 주문은 입금상태를 변경할 수 없습니다.', 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
$orderModel->update($soIdx, ['so_paid' => $paid]);
|
||||
|
||||
return $this->response->setJSON(['ok' => true, 'so_idx' => $soIdx, 'paid' => $paid, 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 전화접수 관리 — 봉투코드 스캔으로 즉시 판매·포장 처리(JSON 응답).
|
||||
* 선택된 주문의 판매소로 판매 기록(bag_sale) + 재고 차감 + 팩코드 sold 전환 +
|
||||
@@ -7921,6 +8016,11 @@ SQL;
|
||||
return $this->response->setJSON(['ok' => false, 'message' => '선택한 주문을 사용할 수 없습니다.', 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
// 입금확인(so_paid=1)이 안 된 주문은 포장(판매) 스캔 불가.
|
||||
if ((int) ($order->so_paid ?? 0) !== 1) {
|
||||
return $this->response->setJSON(['ok' => false, 'message' => '입금확인이 완료되지 않은 주문입니다. 입금확인 후 포장하세요.', 'csrf' => csrf_hash()]);
|
||||
}
|
||||
|
||||
$scan = $this->resolveDesignatedSaleBarcode($lgIdx, $barcode);
|
||||
if (! ($scan['ok'] ?? false)) {
|
||||
return $this->response->setJSON(array_merge($scan, ['csrf' => csrf_hash()]));
|
||||
|
||||
@@ -44,7 +44,11 @@ class Home extends BaseController
|
||||
}
|
||||
helper('admin');
|
||||
|
||||
return view('bag/layout/workspace');
|
||||
// 계정별 저장된 탭 상태(자동 복원). 없으면 'null'.
|
||||
$savedWorkspaceJson = (new \App\Controllers\Bag())
|
||||
->loadWorkspaceTabsState((int) (session()->get('mb_idx') ?? 0));
|
||||
|
||||
return view('bag/layout/workspace', ['savedWorkspaceJson' => $savedWorkspaceJson]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,7 @@ if (window.top !== window.self) { try { window.top.location.href = <?= json_enco
|
||||
<header class="bg-navy text-white h-12 flex items-center justify-between px-4 shrink-0 shadow">
|
||||
<a href="<?= base_url() ?>" class="flex items-center gap-2 shrink-0 tracking-tight hover:opacity-90" title="GBLS (Garbage Bag Logistics System)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 text-white shrink-0" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
<path fill="currentColor" fill-rule="evenodd" d="M6 7.5 H18 V19.5 A1.5 1.5 0 0 1 16.5 21 H7.5 A1.5 1.5 0 0 1 6 19.5 Z M6 7.5 L8.5 4.2 H15.5 L18 7.5 Z M10.2 5.2 h3.6 a0.5 0.5 0 0 1 0 1 h-3.6 a0.5 0.5 0 0 1 0 -1 z"/>
|
||||
</svg>
|
||||
<span class="leading-none flex flex-col">
|
||||
<strong class="text-base font-extrabold tracking-wide">GBLS</strong>
|
||||
|
||||
@@ -788,6 +788,16 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 박스수량 입력 중 Enter → 다음 봉투의 박스수량 입력칸으로 이동(#39)
|
||||
selectedBody.addEventListener('keydown', (event) => {
|
||||
if (event.key !== 'Enter' || !event.target.classList.contains('item-qty-box')) return;
|
||||
event.preventDefault();
|
||||
const inputs = Array.from(selectedBody.querySelectorAll('.item-qty-box'));
|
||||
const next = inputs[inputs.indexOf(event.target) + 1];
|
||||
if (next) { next.focus(); next.select(); }
|
||||
else { event.target.blur(); }
|
||||
});
|
||||
|
||||
referenceRows.forEach((row) => {
|
||||
row.addEventListener('click', (event) => {
|
||||
const button = event.target.closest('.js-toggle-bag');
|
||||
|
||||
@@ -191,9 +191,12 @@ if ($effectiveLgIdx) {
|
||||
|
||||
var STORE_KEY = 'jrj_ws_tabs';
|
||||
var WS_OWNER = '<?= (string) (session()->get('mb_idx') ?? '') ?>'; // 탭 저장 소유자(로그인 사용자) 식별
|
||||
function persist() {
|
||||
try {
|
||||
sessionStorage.setItem(STORE_KEY, JSON.stringify({
|
||||
var WS_SAVE_URL = '<?= site_url('bag/pref/workspace-tabs') ?>';
|
||||
var WS_CSRF_NAME = '<?= csrf_token() ?>';
|
||||
var wsCsrfHash = '<?= csrf_hash() ?>';
|
||||
var wsSaveTimer = null;
|
||||
function wsStateObj() {
|
||||
return {
|
||||
owner: WS_OWNER,
|
||||
tabs: order.map(function (id) { return { url: tabs[id].url, title: tabs[id].title }; }),
|
||||
layout: layout,
|
||||
@@ -201,8 +204,20 @@ if ($effectiveLgIdx) {
|
||||
vRatio: vRatio,
|
||||
hRatio: hRatio,
|
||||
slots: slots.map(function (id) { return (id && tabs[id]) ? tabs[id].url : null; })
|
||||
}));
|
||||
} catch (e) {}
|
||||
};
|
||||
}
|
||||
function persist() {
|
||||
var obj = wsStateObj();
|
||||
var json = JSON.stringify(obj);
|
||||
try { sessionStorage.setItem(STORE_KEY, json); } catch (e) {}
|
||||
// 계정(DB)에 저장 → 다음 로그인/다른 기기에서도 자동 복원 (연속 변경은 디바운스)
|
||||
clearTimeout(wsSaveTimer);
|
||||
wsSaveTimer = setTimeout(function () {
|
||||
var b = new URLSearchParams();
|
||||
b.set(WS_CSRF_NAME, wsCsrfHash); b.set('state', json);
|
||||
fetch(WS_SAVE_URL, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: b.toString() })
|
||||
.then(function (r) { return r.json(); }).then(function (d) { if (d && d.csrf) wsCsrfHash = d.csrf; }).catch(function () {});
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 분할 칸 헤더·빈칸 안내 요소 4개 미리 생성
|
||||
@@ -560,11 +575,19 @@ if ($effectiveLgIdx) {
|
||||
});
|
||||
});
|
||||
|
||||
// 첫 화면: 세션 저장 복원(레이아웃·분할 배치 포함), 없으면 대시보드 1분할
|
||||
// 첫 화면: ① 계정(DB) 저장 자동복원 → ② 세션 저장 → ③ 없으면 대시보드 1분할
|
||||
var SERVER_STATE = <?= $savedWorkspaceJson ?? 'null' ?>;
|
||||
(function restore() {
|
||||
var saved = null;
|
||||
// ① 계정 DB에 저장된 상태 우선(다음 로그인·다른 기기에서도 복원)
|
||||
if (SERVER_STATE && SERVER_STATE.tabs && SERVER_STATE.tabs.length) {
|
||||
saved = SERVER_STATE;
|
||||
}
|
||||
// ② 없으면 이 브라우저 세션 저장 사용
|
||||
if (!saved) {
|
||||
try { saved = JSON.parse(sessionStorage.getItem(STORE_KEY) || 'null'); } catch (e) {}
|
||||
if (saved && saved.owner !== WS_OWNER) { try { sessionStorage.removeItem(STORE_KEY); } catch (e) {} saved = null; }
|
||||
}
|
||||
if (saved && saved.tabs && saved.tabs.length) {
|
||||
saved.tabs.forEach(function (t) { if (t && t.url) openTab(t.url, t.title, { noFocus: true }); });
|
||||
layout = (saved.layout === 'lr' || saved.layout === 'tb' || saved.layout === 'quad') ? saved.layout : 'single';
|
||||
|
||||
@@ -187,7 +187,7 @@ unset($g);
|
||||
<th class="text-right">금액</th>
|
||||
<th class="text-right">수량</th>
|
||||
<th class="text-right">금액</th>
|
||||
<th class="text-right">판매수량</th>
|
||||
<th class="text-right">판매수량(팩)</th>
|
||||
<th class="text-right">금액</th>
|
||||
<th class="text-center">B</th>
|
||||
<th class="text-center">P</th>
|
||||
@@ -212,7 +212,7 @@ unset($g);
|
||||
<td class="text-right px-2"><?= number_format($r['box']) ?></td>
|
||||
<td class="text-right px-2"><?= number_format($boxPrice) ?></td>
|
||||
<td class="text-right px-2"><?= number_format($r['price']) ?></td>
|
||||
<td><input class="border border-gray-300 rounded px-2 py-1 text-sm w-full text-right item-qty-input" name="item_qty[]" type="number" min="0" value="0"/></td>
|
||||
<td><input class="border border-gray-300 rounded px-2 py-1 text-sm w-full text-right item-qty-input item-pack-input" type="number" min="0" value="0"/><input type="hidden" name="item_qty[]" class="item-qty-hidden" value="0"/></td>
|
||||
<td class="text-right px-2 item-amount-cell">0</td>
|
||||
<td class="text-center item-box-cell">0</td>
|
||||
<td class="text-center item-pack-cell">0</td>
|
||||
@@ -330,12 +330,18 @@ unset($g);
|
||||
}
|
||||
|
||||
function calcRow(row) {
|
||||
const qtyInput = row.querySelector('.item-qty-input');
|
||||
const qty = parseInt(qtyInput.value || '0', 10) || 0;
|
||||
const qtyInput = row.querySelector('.item-pack-input');
|
||||
const hiddenQty = row.querySelector('.item-qty-hidden');
|
||||
const packQty = parseInt(qtyInput.value || '0', 10) || 0; // 입력값 = 팩 수
|
||||
const unitPrice = parseInt(row.dataset.unitPrice || '0', 10) || 0;
|
||||
const boxSheets = parseInt(row.dataset.boxSheets || '0', 10) || 0;
|
||||
const packSheets = parseInt(row.dataset.packSheets || '0', 10) || 0;
|
||||
|
||||
// 팩당 낱장 수(팩 매수 미설정 봉투는 1:1로 처리)
|
||||
const mult = packSheets > 0 ? packSheets : 1;
|
||||
const qty = packQty * mult; // 실제 낱장 수 → 서버로 전송
|
||||
if (hiddenQty) hiddenQty.value = String(qty);
|
||||
|
||||
let box = 0;
|
||||
let pack = 0;
|
||||
let sheet = qty;
|
||||
@@ -359,14 +365,14 @@ unset($g);
|
||||
row.querySelector('.item-pack-cell').textContent = pack ? nf(pack) : '';
|
||||
row.querySelector('.item-sheet-cell').textContent = sheet ? nf(sheet) : '';
|
||||
|
||||
return { qty, amount, box, pack, sheet };
|
||||
return { packQty, amount, box, pack, sheet };
|
||||
}
|
||||
|
||||
function recalcAllRows() {
|
||||
let sumQty = 0, sumAmount = 0, sumBox = 0, sumPack = 0, sumSheet = 0;
|
||||
document.querySelectorAll('.order-row').forEach((row) => {
|
||||
const r = calcRow(row);
|
||||
sumQty += r.qty;
|
||||
sumQty += r.packQty;
|
||||
sumAmount += r.amount;
|
||||
sumBox += r.box;
|
||||
sumPack += r.pack;
|
||||
|
||||
@@ -69,12 +69,14 @@
|
||||
<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><span class="font-semibold text-gray-700 inline-block w-20">입금상태</span> <span id="detail-paid-status" class="font-semibold">-</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 px-1">
|
||||
<span class="text-sm font-semibold text-gray-700">접수 품목 내역</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" id="btn-toggle-paid" class="border border-emerald-300 text-emerald-700 px-3 py-1 rounded-sm text-sm hover:bg-emerald-50" disabled>입금확인</button>
|
||||
<button type="submit" id="btn-save" class="bg-btn-search text-white px-3 py-1 rounded-sm text-sm shadow hover:opacity-90" disabled>주문 수정 저장</button>
|
||||
<button type="button" id="btn-receipt" class="border border-gray-300 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50" disabled>입금자 영수증 출력</button>
|
||||
<button type="submit" id="btn-cancel-order" form="order-cancel-form" class="border border-red-300 text-red-600 px-3 py-1 rounded-sm text-sm hover:bg-red-50" disabled>주문 취소</button>
|
||||
@@ -238,6 +240,8 @@
|
||||
const btnSave = document.getElementById('btn-save');
|
||||
const btnCancel = document.getElementById('btn-cancel-order');
|
||||
const btnReceipt = document.getElementById('btn-receipt');
|
||||
const btnTogglePaid = document.getElementById('btn-toggle-paid');
|
||||
const paidApi = new URL('<?= base_url('bag/order/phone/manage/paid') ?>', window.location.href).pathname;
|
||||
const receiptBase = '<?= base_url('bag/order/phone/receipt') ?>';
|
||||
btnReceipt?.addEventListener('click', () => {
|
||||
const id = inputSoIdx.value;
|
||||
@@ -252,6 +256,43 @@
|
||||
|
||||
const nf = (n) => new Intl.NumberFormat('ko-KR').format(n || 0);
|
||||
|
||||
function paintPaidButton(order) {
|
||||
if (!btnTogglePaid) return;
|
||||
const paid = order && Number(order.so_paid) === 1;
|
||||
btnTogglePaid.textContent = paid ? '입금확인 취소' : '입금확인';
|
||||
btnTogglePaid.className = paid
|
||||
? 'border border-gray-300 text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50'
|
||||
: 'border border-emerald-300 text-emerald-700 px-3 py-1 rounded-sm text-sm hover:bg-emerald-50';
|
||||
}
|
||||
|
||||
btnTogglePaid?.addEventListener('click', async () => {
|
||||
const id = inputSoIdx.value;
|
||||
if (!id) return;
|
||||
const o = orderMap.get(String(id));
|
||||
if (!o) return;
|
||||
const nextPaid = Number(o.so_paid) === 1 ? 0 : 1;
|
||||
if (nextPaid === 0 && !confirm('입금확인을 취소하면 이 주문은 포장(스캔)이 차단됩니다.\n계속할까요?')) return;
|
||||
const body = new URLSearchParams();
|
||||
body.set(csrfName, csrfHash);
|
||||
body.set('so_idx', String(id));
|
||||
body.set('paid', String(nextPaid));
|
||||
btnTogglePaid.disabled = true;
|
||||
try {
|
||||
const res = await fetch(paidApi, { method: 'POST', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body });
|
||||
const data = await res.json();
|
||||
if (data && data.csrf) csrfHash = data.csrf;
|
||||
if (!data || !data.ok) { alert((data && data.message) || '처리에 실패했습니다.'); btnTogglePaid.disabled = false; return; }
|
||||
o.so_paid = nextPaid;
|
||||
setHeader(o);
|
||||
paintPaidButton(o);
|
||||
btnTogglePaid.disabled = false;
|
||||
renderList(); // 리스트의 입금 표시 갱신
|
||||
} catch (e) {
|
||||
alert('네트워크 오류로 처리하지 못했습니다.');
|
||||
btnTogglePaid.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
function setHeader(order) {
|
||||
var t = function (id, v) { document.getElementById(id).textContent = (v === undefined || v === null || v === '') ? '-' : v; };
|
||||
t('detail-so-no', order ? displayNo(order) : '');
|
||||
@@ -263,6 +304,12 @@
|
||||
t('detail-shop-addr', order ? order.ds_addr : '');
|
||||
t('detail-order-date', order ? order.so_order_date : '');
|
||||
t('detail-status', order ? ((order.so_status === 'cancelled') ? '취소' : '정상') : '');
|
||||
var ps = document.getElementById('detail-paid-status');
|
||||
if (ps) {
|
||||
var paid = order && Number(order.so_paid) === 1;
|
||||
ps.textContent = order ? (paid ? '입금완료' : '미입금') : '-';
|
||||
ps.style.color = order ? (paid ? '#059669' : '#e11d48') : '';
|
||||
}
|
||||
// 배달일 — 수정 가능한 date 입력
|
||||
var dd = document.getElementById('detail-delivery-date-input');
|
||||
if (dd) {
|
||||
@@ -346,6 +393,7 @@
|
||||
btnSave.disabled = isCancelled;
|
||||
btnCancel.disabled = isCancelled;
|
||||
if (btnReceipt) btnReceipt.disabled = false;
|
||||
if (btnTogglePaid) { btnTogglePaid.disabled = isCancelled; paintPaidButton(order); }
|
||||
|
||||
renderPacking(order); // 포장 명세 탭 동기화
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ $linkClass = $linkClass ?? 'app-brand flex items-center gap-2 shrink-0 text-base
|
||||
?>
|
||||
<a href="<?= esc($href) ?>" class="<?= esc($linkClass, 'attr') ?>" title="GBLS (Garbage Bag Logistics System)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 text-blue-900 translate-y-[1px] shrink-0" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
<path fill="currentColor" fill-rule="evenodd" d="M6 7.5 H18 V19.5 A1.5 1.5 0 0 1 16.5 21 H7.5 A1.5 1.5 0 0 1 6 19.5 Z M6 7.5 L8.5 4.2 H15.5 L18 7.5 Z M10.2 5.2 h3.6 a0.5 0.5 0 0 1 0 1 h-3.6 a0.5 0.5 0 0 1 0 -1 z"/>
|
||||
</svg>
|
||||
<span class="leading-none flex flex-col">
|
||||
<strong class="font-extrabold tracking-wide">GBLS</strong>
|
||||
|
||||
@@ -9,7 +9,7 @@ $brandHref = $brandHref ?? base_url('dashboard/gov-portal');
|
||||
?>
|
||||
<a href="<?= esc($brandHref) ?>" class="gov-portal-brand">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
<path fill="currentColor" fill-rule="evenodd" d="M6 7.5 H18 V19.5 A1.5 1.5 0 0 1 16.5 21 H7.5 A1.5 1.5 0 0 1 6 19.5 Z M6 7.5 L8.5 4.2 H15.5 L18 7.5 Z M10.2 5.2 h3.6 a0.5 0.5 0 0 1 0 1 h-3.6 a0.5 0.5 0 0 1 0 -1 z"/>
|
||||
</svg>
|
||||
<span style="display:inline-flex;flex-direction:column;line-height:1.02;">
|
||||
<strong style="font-size:1.02rem;font-weight:800;letter-spacing:.5px;">GBLS</strong>
|
||||
|
||||
@@ -28,7 +28,7 @@ tailwind.config = {
|
||||
<header class="bg-navy text-white h-12 flex items-center justify-between px-4 shrink-0 shadow">
|
||||
<a href="<?= base_url() ?>" class="flex items-center gap-2 tracking-tight hover:opacity-90" title="GBLS (Garbage Bag Logistics System)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 text-white shrink-0" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
<path fill="currentColor" fill-rule="evenodd" d="M6 7.5 H18 V19.5 A1.5 1.5 0 0 1 16.5 21 H7.5 A1.5 1.5 0 0 1 6 19.5 Z M6 7.5 L8.5 4.2 H15.5 L18 7.5 Z M10.2 5.2 h3.6 a0.5 0.5 0 0 1 0 1 h-3.6 a0.5 0.5 0 0 1 0 -1 z"/>
|
||||
</svg>
|
||||
<span class="leading-none flex flex-col">
|
||||
<strong class="text-base font-extrabold tracking-wide">GBLS</strong>
|
||||
@@ -46,7 +46,7 @@ tailwind.config = {
|
||||
<div class="bg-gradient-to-br from-navy to-[#007bff] text-white px-8 py-8 text-center">
|
||||
<div class="inline-flex h-14 w-14 items-center justify-center rounded-full bg-white/15 mb-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-7 w-7 text-white" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
<path fill="currentColor" fill-rule="evenodd" d="M6 7.5 H18 V19.5 A1.5 1.5 0 0 1 16.5 21 H7.5 A1.5 1.5 0 0 1 6 19.5 Z M6 7.5 L8.5 4.2 H15.5 L18 7.5 Z M10.2 5.2 h3.6 a0.5 0.5 0 0 1 0 1 h-3.6 a0.5 0.5 0 0 1 0 -1 z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 class="text-xl font-bold">종량제 쓰레기봉투 물류시스템</h1>
|
||||
|
||||
5
writable/database/menu_rename_phone_to_order.sql
Normal file
5
writable/database/menu_rename_phone_to_order.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 사용자 의견 #35: 메뉴 '전화 접수 관리' → '주문접수관리' 개명
|
||||
-- 실행: mysql -u jongryangje -p jongryangje_dev < writable/database/menu_rename_phone_to_order.sql
|
||||
-- 멱등(이미 바뀌었으면 0건).
|
||||
|
||||
UPDATE `menu` SET `mm_name` = '주문접수관리' WHERE `mm_name` = '전화 접수 관리';
|
||||
@@ -177,7 +177,7 @@ INSERT INTO menu (mt_idx, lg_idx, mm_name, mm_link, mm_pidx, mm_dep, mm_num, mm_
|
||||
SELECT @mt_site, 1, t.mm_name,
|
||||
CASE t.mm_name
|
||||
WHEN '전화 접수' THEN 'bag/shop-orders'
|
||||
WHEN '전화 접수 관리' THEN 'bag/shop-orders'
|
||||
WHEN '주문접수관리' THEN 'bag/shop-orders'
|
||||
WHEN '지정 판매소 판매' THEN 'bag/sale/create'
|
||||
WHEN '지정 판매소 반품' THEN 'bag/bag-sales'
|
||||
WHEN '지정 판매소 판매 취소' THEN 'bag/bag-sales'
|
||||
@@ -187,7 +187,7 @@ SELECT @mt_site, 1, t.mm_name,
|
||||
@parent_sales, 1, t.mm_num, 0, '', 'Y'
|
||||
FROM (
|
||||
SELECT 0 AS mm_num, '전화 접수' AS mm_name UNION ALL
|
||||
SELECT 1, '전화 접수 관리' UNION ALL
|
||||
SELECT 1, '주문접수관리' UNION ALL
|
||||
SELECT 2, '지정 판매소 판매' UNION ALL
|
||||
SELECT 3, '지정 판매소 반품' UNION ALL
|
||||
SELECT 4, '지정 판매소 판매 취소' UNION ALL
|
||||
|
||||
Reference in New Issue
Block a user