diff --git a/src/app/(main)/m/admin/orders/page.tsx b/src/app/(main)/m/admin/orders/page.tsx index c36cfee..a7a7f1b 100644 --- a/src/app/(main)/m/admin/orders/page.tsx +++ b/src/app/(main)/m/admin/orders/page.tsx @@ -456,24 +456,35 @@ function StatementPreview({ }); }; - // 비고 저장 + // 비고 저장 — 명세표 + 왼쪽 리스트 모두 갱신 const saveRemark = async (lineObjid: string, remark: string) => { const res = await fetch("/api/m/orders/items/remark", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ lineObjid, remark }), }); const j = await res.json(); - if (j.success) onReload(); + if (j.success) { onReload(); onReloadList(); } else Swal.fire({ icon: "error", title: "비고 저장 실패", text: j.message }); }; + // ITEM 라인 수량 즉시 저장 — items/update API + const saveItemQty = async (lineObjid: string, qty: number) => { + const res = await fetch("/api/m/orders/items/update", { + method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ orderObjid: order.OBJID, lines: [{ objid: lineObjid, qty }] }), + }); + const j = await res.json(); + if (j.success) { onReload(); onReloadList(); } + else Swal.fire({ icon: "error", title: "수량 저장 실패", text: j.message }); + }; + const upsertExtra = async (line: { objid?: string; kind: "DELIVERY" | "CHARTER"; label: string; unitPrice: number; qty: number }) => { const res = await fetch("/api/m/orders/lines/save", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ orderObjid: order.OBJID, lines: [line] }), }); const j = await res.json(); - if (j.success) onReload(); + if (j.success) { onReload(); onReloadList(); } else Swal.fire({ icon: "error", title: "저장 실패", text: j.message }); }; const deleteExtra = async (objid: string) => { @@ -484,7 +495,7 @@ function StatementPreview({ body: JSON.stringify({ orderObjid: order.OBJID, lines: [{ objid, kind: "CHARTER", unitPrice: 0, qty: 1, delete: true }] }), }); const j = await res.json(); - if (j.success) onReload(); + if (j.success) { onReload(); onReloadList(); } else Swal.fire({ icon: "error", title: "삭제 실패", text: j.message }); }; const addNewExtra = (kind: "DELIVERY" | "CHARTER") => { @@ -671,7 +682,11 @@ function StatementPreview({ {isExtra ? "-" : fmt(it.STOCK_QTY)} - {fmt(it.QTY)} + + {editable + ? saveItemQty(it.OBJID, q)} /> + : fmt(it.QTY)} + {fmt(it.UNIT_PRICE)} {fmt(it.SUPPLY_AMOUNT)} {it.IS_TAX_FREE === "Y" ? "-" : fmt(it.VAT_AMOUNT)} @@ -752,11 +767,16 @@ function ExtraRow({ line, displaySeq, editable, onSave, onDelete, onSaveRemark } const total = Math.round(unitPrice * qty); const supply = Math.round(total / 1.1); const vat = total - supply; - const dirty = label !== (line.EXTRA_LABEL || line.ITEM_NAME) - || unitPrice !== Number(line.UNIT_PRICE) - || qty !== Number(line.QTY); const isDelivery = line.KIND === "DELIVERY"; + // onBlur 시 자동 저장 (값이 바뀐 경우만). V 버튼 제거. + const commit = () => { + const dirty = label !== (line.EXTRA_LABEL || line.ITEM_NAME) + || unitPrice !== Number(line.UNIT_PRICE) + || qty !== Number(line.QTY); + if (dirty && qty > 0 && unitPrice >= 0) onSave({ label, unitPrice, qty }); + }; + return ( {displaySeq} @@ -767,6 +787,8 @@ function ExtraRow({ line, displaySeq, editable, onSave, onDelete, onSaveRemark } setLabel(e.target.value)} + onBlur={commit} + onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }} className="h-6 px-1.5 border border-slate-200 rounded text-[11px] bg-white w-[calc(100%-50px)] inline" /> @@ -775,11 +797,15 @@ function ExtraRow({ line, displaySeq, editable, onSave, onDelete, onSaveRemark } setQty(Number(e.target.value))} + onBlur={commit} + onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }} className="w-full h-6 px-1 border border-slate-200 rounded text-[11px] text-right tabular-nums bg-white" /> setUnitPrice(Number(e.target.value))} + onBlur={commit} + onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }} className="w-full h-6 px-1 border border-slate-200 rounded text-[11px] text-right tabular-nums bg-white" /> {Number(supply).toLocaleString("ko-KR")} @@ -791,21 +817,9 @@ function ExtraRow({ line, displaySeq, editable, onSave, onDelete, onSaveRemark } : {line.REMARK || ""}} -
- {dirty && ( - - )} - -
+ ); @@ -900,3 +914,24 @@ function RemarkInput({ initial, onSave }: { initial: string; onSave: (r: string) ); } + +// ITEM 라인 수량 인라인 인풋 — onBlur / Enter 시 자동 저장 +function QtyInput({ initial, onSave }: { initial: number; onSave: (q: number) => void }) { + const [val, setVal] = useState(String(initial)); + useEffect(() => { setVal(String(initial)); }, [initial]); + const commit = () => { + const n = Number(val); + if (!Number.isFinite(n) || n <= 0) { setVal(String(initial)); return; } + if (n === initial) return; + onSave(n); + }; + return ( + setVal(e.target.value)} + onBlur={commit} + onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }} + className="w-16 h-6 px-1 border border-slate-200 rounded text-[11px] text-right tabular-nums bg-white" + /> + ); +}