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

238 lines
11 KiB
PHP

@extends('admin.layouts.app')
@section('title', 'SKU 수정')
@section('page_title', 'SKU 수정')
@section('page_desc', 'SKU(권종/가격)를 수정합니다.')
@push('head')
<style>
/* skus edit only (admins edit 스타일 준수) */
.lbtn{padding:8px 12px;font-size:13px;border-radius:12px;line-height:1.1;text-decoration:none;display:inline-flex;align-items:center;justify-content:center;gap:6px;
border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.06);color:inherit;cursor:pointer;}
.lbtn:hover{background:rgba(255,255,255,.10);text-decoration:none;}
.lbtn--primary{background:rgba(59,130,246,.88);border-color:rgba(59,130,246,.95);color:#fff;}
.lbtn--primary:hover{background:rgba(59,130,246,.98);}
.lbtn--danger{background:rgba(244,63,94,.88);border-color:rgba(244,63,94,.95);color:#fff;}
.lbtn--danger:hover{background:rgba(244,63,94,.98);}
.lbtn--ghost{background:transparent;}
.lbtn--wide{padding:10px 14px;font-weight:800;}
.pill{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;font-size:12px;
border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.06);}
.pill--ok{border-color:rgba(34,197,94,.35);background:rgba(34,197,94,.12);}
.pill--bad{border-color:rgba(244,63,94,.35);background:rgba(244,63,94,.10);}
.pill--muted{opacity:.9;}
.mono{padding:4px 8px;border-radius:10px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.10);
font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:12px;}
.kvgrid{display:grid;grid-template-columns:1fr;gap:12px;}
@media (min-width: 980px){ .kvgrid{grid-template-columns:1fr 1fr 1fr;} }
.kv{padding:14px;border-radius:16px;border:1px solid rgba(255,255,255,.10);background:rgba(255,255,255,.04);}
.kv .k{font-size:12px;opacity:.8;margin-bottom:6px;}
.kv .v{font-weight:900;}
.actions{position:sticky;bottom:10px;z-index:5;margin-top:12px;
display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;align-items:center;
padding:12px;border-radius:16px;border:1px solid rgba(255,255,255,.10);background:rgba(0,0,0,.25);backdrop-filter:blur(10px);}
.actions__right{display:flex;gap:8px;flex-wrap:wrap;align-items:center;}
.grid{display:grid;grid-template-columns:1fr;gap:12px;max-width:900px;}
@media (min-width: 980px){ .grid{grid-template-columns:1fr 1fr;} }
.grid .span2{grid-column:1 / -1;}
.help{font-size:12px;margin-top:6px;}
</style>
@endpush
@section('content')
@php
$p = $sku ?? null;
$qs = request()->only(['q','category_id','product_id','status','page']);
$st = (string)old('status', (string)($p->status ?? 'active'));
$pill = $st === 'active' ? 'pill--ok' : 'pill--bad';
$stText = $st === 'active' ? '노출' : '숨김';
$face = (int)old('face_value', (int)($p->face_value ?? 0));
$normal = (int)old('normal_price', (int)($p->normal_price ?? 0));
$rate = (string)old('discount_rate', (string)($p->discount_rate ?? '0.00'));
$sale = (int)($p->sale_price ?? 0);
@endphp
<div class="a-card" style="padding:16px; margin-bottom:16px;">
<div style="display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:wrap;">
<div>
<div style="font-weight:900; font-size:16px;">SKU 수정</div>
<div class="a-muted" style="font-size:12px; margin-top:4px;">
#{{ (int)($p->id ?? 0) }}
</div>
</div>
<a class="lbtn lbtn--ghost"
href="{{ route('admin.skus.index', $qs) }}">
목록
</a>
</div>
</div>
{{-- 요약 --}}
<div class="kvgrid" style="margin-bottom:16px;">
<div class="kv">
<div class="k">상태</div>
<div class="v"><span class="pill {{ $pill }}"> {{ $stText }}</span></div>
</div>
<div class="kv">
<div class="k">현재 판매가</div>
<div class="v">{{ number_format($sale) }} </div>
</div>
<div class="kv">
<div class="k">재고방식</div>
<div class="v">{{ (string)($p->stock_mode ?? '-') }}</div>
</div>
<div class="kv">
<div class="k">생성</div>
<div class="v">{{ $p->created_at ?? '-' }}</div>
</div>
<div class="kv">
<div class="k">최근 수정</div>
<div class="v">{{ $p->updated_at ?? '-' }}</div>
</div>
<div class="kv">
<div class="k">상품 ID</div>
<div class="v"><span class="mono">{{ (int)($p->product_id ?? 0) }}</span></div>
</div>
</div>
{{-- 수정 --}}
<form id="skuEditForm"
method="POST"
action="{{ route('admin.skus.update', ['id'=>(int)($p->id ?? 0)] ) }}"
onsubmit="this.querySelector('button[type=submit]')?.setAttribute('disabled','disabled');">
@csrf
@method('PUT')
{{-- 저장 목록 복귀 같은 필터/페이지 유지용 --}}
@foreach($qs as $k=>$v)
<input type="hidden" name="{{ $k }}" value="{{ $v }}">
@endforeach
<div class="a-card" style="padding:16px;">
<div class="grid">
<div class="a-field span2">
<label class="a-label">상품</label>
<div class="a-muted" style="font-size:13px;">
상품 변경은 운영상 위험해서(재고/정산/장부 연계) 기본은 고정입니다.
<span class="mono" style="margin-left:8px;">product_id={{ (int)($p->product_id ?? 0) }}</span>
</div>
</div>
<div class="a-field">
<label class="a-label">SKU 코드(선택)</label>
<input class="a-input" name="sku_code" value="{{ old('sku_code', (string)($p->sku_code ?? '')) }}" placeholder="예: GOOGLE_10000">
</div>
<div class="a-field">
<label class="a-label">정렬(작을수록 우선)</label>
<input class="a-input" type="number" name="sort" min="0" value="{{ old('sort', (string)($p->sort ?? '0')) }}">
</div>
<div class="a-field">
<label class="a-label">권면가()</label>
<input class="a-input" type="number" name="face_value" id="face_value" min="0" value="{{ old('face_value', (string)($p->face_value ?? '')) }}">
</div>
<div class="a-field">
<label class="a-label">정상가()</label>
<input class="a-input" type="number" name="normal_price" id="normal_price" min="0" value="{{ old('normal_price', (string)($p->normal_price ?? '')) }}">
</div>
<div class="a-field">
<label class="a-label">할인율(%)</label>
<input class="a-input" type="number" name="discount_rate" id="discount_rate" min="0" max="99.99" step="0.01"
value="{{ old('discount_rate', (string)($p->discount_rate ?? '0.00')) }}">
</div>
<div class="a-field">
<label class="a-label">판매가 미리보기</label>
<div><span class="mono" id="sale_price_preview">-</span></div>
<div class="a-muted help"> 저장 서버에서 계산되어 sale_price에 저장됩니다.</div>
</div>
<div class="a-field">
<label class="a-label">재고방식</label>
<select class="a-input" name="stock_mode">
@php $sm = (string)old('stock_mode', (string)($p->stock_mode ?? 'infinite')); @endphp
<option value="infinite" {{ $sm==='infinite'?'selected':'' }}>무한(infinite)</option>
<option value="limited" {{ $sm==='limited'?'selected':'' }}>한정(limited)</option>
</select>
</div>
<div class="a-field">
<label class="a-label">상태</label>
<select class="a-input" name="status">
@php $stOpt = (string)old('status', (string)($p->status ?? 'active')); @endphp
<option value="active" {{ $stOpt==='active'?'selected':'' }}>노출</option>
<option value="hidden" {{ $stOpt==='hidden'?'selected':'' }}>숨김</option>
</select>
</div>
</div>
<div class="actions">
<div class="a-muted" style="font-size:12px;">
권면가/정상가/할인율 기반으로 판매가가 계산됩니다.
</div>
<div class="actions__right">
<button class="lbtn lbtn--danger"
type="submit"
form="skuDeleteForm"
onclick="return confirm('정말 삭제하시겠습니까? (연동/정산 연결 전까지만 삭제 권장)');">
삭제
</button>
<a class="lbtn lbtn--ghost" href="{{ route('admin.skus.index', $qs) }}">목록</a>
<button class="lbtn lbtn--primary lbtn--wide" type="submit">저장</button>
</div>
</div>
</div>
</form>
{{-- 삭제 (중첩 form 금지) --}}
<form id="skuDeleteForm"
method="POST"
action="{{ route('admin.skus.destroy', ['id'=>(int)($p->id ?? 0)] ) }}">
@csrf
@method('DELETE')
@foreach($qs as $k=>$v)
<input type="hidden" name="{{ $k }}" value="{{ $v }}">
@endforeach
</form>
<script>
(function(){
const n = document.getElementById('normal_price');
const r = document.getElementById('discount_rate');
const out = document.getElementById('sale_price_preview');
const fmt = (x) => {
try { return Number(x).toLocaleString('ko-KR'); } catch (e) { return String(x); }
};
const calc = () => {
const normal = parseInt(n?.value || '0', 10) || 0;
let rate = parseFloat(r?.value || '0') || 0;
if (rate < 0) rate = 0;
if (rate > 99.99) rate = 99.99;
const sale = Math.floor(normal * (100 - rate) / 100);
out.textContent = (normal > 0) ? (fmt(sale) + ' 원') : '-';
};
n?.addEventListener('input', calc);
r?.addEventListener('input', calc);
calc();
})();
</script>
@endsection