238 lines
11 KiB
PHP
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
|