sungro815 b0545ab5b9 관리자 상품관리 완료
웹사이트 상품리스트 상세보기 작업중
2026-02-20 18:11:03 +09:00

231 lines
13 KiB
PHP

@extends('admin.layouts.app')
@section('title', '판매 코드 관리')
@section('page_title', 'API 연동 판매 코드 관리')
@section('page_desc', '외부 연동사(다날 등)와 해당 업체의 고유 상품 코드를 매핑합니다.')
@push('head')
<style>
.grid-layout { display: grid; grid-template-columns: 1fr 350px; gap: 20px; align-items: start; }
@media (max-width: 980px) { .grid-layout { grid-template-columns: 1fr; } }
.cat-list { background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.10); border-radius: 12px; }
.cat-item { padding: 10px 16px; border-bottom: 1px solid rgba(255,255,255,.05); display: flex; justify-content: space-between; align-items: center; transition: background 0.2s; }
.cat-group:last-child > .cat-item, .cat-children > .cat-item:last-child { border-bottom: none; }
.depth-2 { padding-left: 40px; background: rgba(0,0,0,.15); }
.cat-info { display: flex; align-items: center; gap: 10px; }
.cat-actions { display: flex; align-items: center; gap: 4px; }
.btn-sort { padding: 4px 8px; font-size: 11px; }
</style>
@endpush
@section('content')
<div class="grid-layout">
<div class="a-card" style="padding:16px;">
<div style="font-weight:900; font-size:16px; margin-bottom:16px;">🏢 연동사 📦 상품코드 목록</div>
<div class="cat-list">
@forelse($tree as $pv)
<div class="cat-group">
<div class="cat-item" style="background: rgba(59,130,246,.1);">
<div class="cat-info">
<span class="pill {{ $pv['is_active'] ? 'pill--ok' : 'pill--muted' }}">
{{ $pv['is_active'] ? 'ON' : 'OFF' }}
</span>
<strong style="color:#60a5fa;">{{ $pv['name'] }}</strong>
<span class="mono">[{{ $pv['code'] }}]</span>
</div>
<div class="cat-actions">
<button type="button" class="lbtn lbtn--sm lbtn--ghost" onclick="editProvider({{ json_encode($pv) }})">연동사 수정</button>
<form action="{{ route('admin.sale-codes.provider.destroy', $pv['id']) }}" method="POST" onsubmit="return confirm('이 연동사를 삭제하시겠습니까?\n하위에 등록된 상품 코드가 없어야 삭제 가능합니다.');" style="margin:0;">
@csrf @method('DELETE')
<button type="submit" class="lbtn lbtn--sm lbtn--danger">삭제</button>
</form>
</div>
</div>
<div class="cat-children">
@foreach($pv['children'] as $cd)
<div class="cat-item depth-2" data-id="{{ $cd['id'] }}">
<div class="cat-info">
<span class="pill {{ $cd['is_active'] ? 'pill--ok' : 'pill--muted' }}">
{{ $cd['is_active'] ? 'ON' : 'OFF' }}
</span>
<span>{{ $cd['name'] }}</span>
<span class="a-muted" style="font-size:12px;">({{ $cd['api_code'] }})</span>
</div>
<div class="cat-actions">
<button type="button" class="lbtn lbtn--ghost btn-sort" onclick="moveRow(this, -1)"></button>
<button type="button" class="lbtn lbtn--ghost btn-sort" onclick="moveRow(this, 1)"></button>
<button type="button" class="lbtn lbtn--sm lbtn--ghost" style="margin-left:8px;" onclick="editCode({{ json_encode($cd) }})">수정</button>
<form action="{{ route('admin.sale-codes.code.destroy', $cd['id']) }}" method="POST" onsubmit="return confirm('이 상품 코드를 매핑에서 삭제하시겠습니까?');" style="margin:0;">
@csrf @method('DELETE')
<button type="submit" class="lbtn lbtn--sm lbtn--danger">삭제</button>
</form>
</div>
</div>
@endforeach
</div>
</div>
@empty
<div style="padding: 20px; text-align: center;" class="a-muted">등록된 연동사 코드가 없습니다.</div>
@endforelse
</div>
</div>
<div>
<div class="a-card" style="padding:16px; margin-bottom:20px; border-top: 3px solid rgba(52,211,153,.8);">
<div style="font-weight:900; font-size:16px; margin-bottom:16px;" id="codeTitle">📦 상품 코드 등록</div>
<form id="codeForm" method="POST" action="{{ route('admin.sale-codes.code.store') }}">
@csrf
<input type="hidden" name="_method" id="codeMethod" value="POST">
<div style="display:grid; gap:12px;">
<div class="a-field">
<label class="a-label">연동사 선택</label>
<select class="a-input" name="provider_id" id="codeProviderId" required>
<option value="">-- 연동사 선택 --</option>
@foreach($tree as $pv)
<option value="{{ $pv['id'] }}">{{ $pv['name'] }}</option>
@endforeach
</select>
</div>
<div class="a-field">
<label class="a-label">실제 API 상품 코드 (: CULTURE)</label>
<input class="a-input" name="api_code" id="codeApi" required>
</div>
<div class="a-field">
<label class="a-label">상품 매핑 명칭 (: 문화상품권)</label>
<input class="a-input" name="name" id="codeName" required>
</div>
<div class="a-field">
<label class="a-label">사용 여부</label>
<select class="a-input" name="is_active" id="codeActive">
<option value="1">ON (사용)</option>
<option value="0">OFF (숨김)</option>
</select>
</div>
<div style="display:flex; gap:10px; margin-top:10px;">
<button type="button" class="lbtn lbtn--ghost" style="flex:1;" onclick="resetCodeForm()">신규등록 초기화</button>
<button type="submit" class="lbtn lbtn--primary" style="flex:1;">저장</button>
</div>
</div>
</form>
</div>
<div class="a-card" style="padding:16px; border-top: 3px solid rgba(96,165,250,.8);">
<div style="font-weight:900; font-size:16px; margin-bottom:16px;" id="pvTitle">🏢 신규 연동사 (Provider) 등록</div>
<form id="pvForm" method="POST" action="{{ route('admin.sale-codes.provider.store') }}">
@csrf
<input type="hidden" name="_method" id="pvMethod" value="POST">
<div style="display:grid; gap:12px;">
<div class="a-field">
<label class="a-label">연동사 코드 (: DANAL)</label>
<input class="a-input" name="code" id="pvCode" required>
</div>
<div class="a-field">
<label class="a-label">연동사 노출명 (: 다날)</label>
<input class="a-input" name="name" id="pvName" required>
</div>
<div class="a-field">
<label class="a-label">사용 여부</label>
<select class="a-input" name="is_active" id="pvActive">
<option value="1">ON (전체 사용)</option>
<option value="0">OFF (전체 장애/중단)</option>
</select>
</div>
<div style="display:flex; gap:10px; margin-top:10px;">
<button type="button" class="lbtn lbtn--ghost" style="flex:1;" onclick="resetPvForm()">신규등록 초기화</button>
<button type="submit" class="lbtn lbtn--primary" style="flex:1;">저장</button>
</div>
</div>
</form>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
const baseUrl = '{{ route('admin.sale-codes.index') }}';
// 상품 코드 수정 세팅
function editCode(cd) {
document.getElementById('codeTitle').innerText = '📦 상품 코드 수정 (#'+cd.id+')';
document.getElementById('codeForm').action = baseUrl + '/code/' + cd.id;
document.getElementById('codeMethod').value = 'PUT';
document.getElementById('codeProviderId').value = cd.provider_id;
document.getElementById('codeApi').value = cd.api_code;
document.getElementById('codeName').value = cd.name;
document.getElementById('codeActive').value = cd.is_active;
}
function resetCodeForm() {
document.getElementById('codeTitle').innerText = '📦 상품 코드 등록';
document.getElementById('codeForm').action = '{{ route('admin.sale-codes.code.store') }}';
document.getElementById('codeMethod').value = 'POST';
document.getElementById('codeProviderId').value = '';
document.getElementById('codeApi').value = '';
document.getElementById('codeName').value = '';
document.getElementById('codeActive').value = '1';
}
// 연동사 수정 세팅
function editProvider(pv) {
document.getElementById('pvTitle').innerText = '🏢 연동사 수정 (#'+pv.id+')';
document.getElementById('pvForm').action = baseUrl + '/provider/' + pv.id;
document.getElementById('pvMethod').value = 'PUT';
document.getElementById('pvCode').value = pv.code;
document.getElementById('pvCode').readOnly = true; // 코드는 수정 불가
document.getElementById('pvName').value = pv.name;
document.getElementById('pvActive').value = pv.is_active;
}
function resetPvForm() {
document.getElementById('pvTitle').innerText = '🏢 신규 연동사 등록';
document.getElementById('pvForm').action = '{{ route('admin.sale-codes.provider.store') }}';
document.getElementById('pvMethod').value = 'POST';
document.getElementById('pvCode').value = '';
document.getElementById('pvCode').readOnly = false;
document.getElementById('pvName').value = '';
document.getElementById('pvActive').value = '1';
}
// 드래그 앤 드롭 대신 화살표 버튼 정렬 (상품 코드 전용)
function moveRow(btn, direction) {
const item = btn.closest('.cat-item');
const container = item.parentNode;
if (direction === -1 && item.previousElementSibling) {
container.insertBefore(item, item.previousElementSibling);
saveSort(container);
} else if (direction === 1 && item.nextElementSibling) {
container.insertBefore(item.nextElementSibling, item);
saveSort(container);
}
}
function saveSort(container) {
const ids = Array.from(container.children).map(el => el.getAttribute('data-id'));
fetch('{{ route('admin.sale-codes.code.sort') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'Accept': 'application/json'
},
body: JSON.stringify({ ids: ids })
});
}
</script>
@endpush